250 lines
11 KiB
JavaScript
250 lines
11 KiB
JavaScript
import express from 'express'
|
|
import { coreEnterprises, customerManagers, dictTypes, dictItems } from '../db/seedBaseConfig.js'
|
|
import { nextId } from '../utils/id.js'
|
|
import { paginate } from '../utils/pagination.js'
|
|
import { sendOk, sendFail } from '../utils/response.js'
|
|
import { requireAuth } from '../middleware/requireAuth.js'
|
|
|
|
const router = express.Router()
|
|
router.use(requireAuth)
|
|
|
|
// ---------------- 核心企业(渠道) ----------------
|
|
// 2026-07-20:后端核心企业接口真实字段为 channelName/channelNo(渠道名称/渠道编号),
|
|
// 与此前依据的旧版 swagger 快照(enterpriseName/enterpriseCode)不同;此处兼容新旧两种字段名,
|
|
// 便于本地演示环境同时兼容历史数据。
|
|
router.post('/core-enterprise/page', (req, res) => {
|
|
const { channelName, channelNo, enterpriseName, enterpriseCode, organizationId, page, pageSize } = req.body || {}
|
|
const nameKeyword = channelName || enterpriseName
|
|
const noKeyword = channelNo || enterpriseCode
|
|
let list = coreEnterprises
|
|
if (nameKeyword) list = list.filter((e) => (e.channelName || e.enterpriseName)?.includes(nameKeyword))
|
|
if (noKeyword) list = list.filter((e) => (e.channelNo || e.enterpriseCode)?.includes(noKeyword))
|
|
if (organizationId) list = list.filter((e) => e.organizationId === organizationId)
|
|
sendOk(res, paginate(list, page, pageSize))
|
|
})
|
|
|
|
router.post('/core-enterprise/create', (req, res) => {
|
|
const body = req.body || {}
|
|
const channelName = body.channelName || body.enterpriseName
|
|
if (!channelName) return sendFail(res, '渠道名称不能为空', 400)
|
|
if (!(body.channelNo || body.enterpriseCode)) return sendFail(res, '渠道编号不能为空', 400)
|
|
const id = nextId('coreEnterprise')
|
|
const entity = { id, createdAt: new Date().toISOString().slice(0, 19).replace('T', ' '), ...body }
|
|
coreEnterprises.push(entity)
|
|
sendOk(res, entity, '创建成功')
|
|
})
|
|
|
|
router.post('/core-enterprise/update', (req, res) => {
|
|
const { id, ...rest } = req.body || {}
|
|
const entity = coreEnterprises.find((e) => e.id === id)
|
|
if (!entity) return sendFail(res, '核心企业不存在', 404)
|
|
Object.assign(entity, rest)
|
|
sendOk(res, true, '更新成功')
|
|
})
|
|
|
|
router.post('/core-enterprise/delete', (req, res) => {
|
|
const { id } = req.body || {}
|
|
const index = coreEnterprises.findIndex((e) => e.id === id)
|
|
if (index === -1) return sendFail(res, '核心企业不存在', 404)
|
|
coreEnterprises.splice(index, 1)
|
|
sendOk(res, true, '删除成功')
|
|
})
|
|
|
|
// ---------------- 客户经理 ----------------
|
|
router.post('/customer-manager/page', (req, res) => {
|
|
const { managerName, page, pageSize } = req.body || {}
|
|
let list = customerManagers
|
|
if (managerName) list = list.filter((m) => m.managerName.includes(managerName))
|
|
sendOk(res, paginate(list, page, pageSize))
|
|
})
|
|
|
|
router.post('/customer-manager/create', (req, res) => {
|
|
const body = req.body || {}
|
|
if (!body.managerName) return sendFail(res, '姓名不能为空', 400)
|
|
const id = nextId('customerManager')
|
|
const entity = { id, status: 'ACTIVE', remark: '', ...body }
|
|
customerManagers.push(entity)
|
|
sendOk(res, entity, '创建成功')
|
|
})
|
|
|
|
router.post('/customer-manager/update', (req, res) => {
|
|
const { id, ...rest } = req.body || {}
|
|
const entity = customerManagers.find((m) => m.id === id)
|
|
if (!entity) return sendFail(res, '客户经理不存在', 404)
|
|
Object.assign(entity, rest)
|
|
sendOk(res, true, '更新成功')
|
|
})
|
|
|
|
router.post('/customer-manager/delete', (req, res) => {
|
|
const { id } = req.body || {}
|
|
const index = customerManagers.findIndex((m) => m.id === id)
|
|
if (index === -1) return sendFail(res, '客户经理不存在', 404)
|
|
customerManagers.splice(index, 1)
|
|
sendOk(res, true, '删除成功')
|
|
})
|
|
|
|
// ---------------- 动态字典管理:字典类型 ----------------
|
|
// 2026-07-31:已按最新 swagger(swagger_project_scfs_2026-07-31_09-25-57.json,dict_management
|
|
// 分组)核对确认字典类型管理全部 4 个接口的真实路径与字段,不再是前端占位契约:
|
|
// POST /api/dict-management/dict-type/page FindDictTypePageQto{dictTypeCodeLike, dictTypeNameLike, dictCategoryList[], statusList[], page, pageSize}
|
|
// POST /api/dict-management/dict-type/create CreateDictTypeBto{dictTypeCode, dictTypeName, dictCategory, remark, status}
|
|
// POST /api/dict-management/dict-type/update UpdateDictTypeBto{id, dictTypeCode, dictTypeName, status, remark}(不含 dictCategory)
|
|
// POST /api/dict-management/dict-type/delete DeleteDictTypeBto{id, dictTypeCode}
|
|
// dictCategory: NORMAL/CASCADE,status: ENABLED/DISABLED。
|
|
router.post('/dict-management/dict-type/page', (req, res) => {
|
|
const { dictTypeCodeLike, dictTypeNameLike, dictCategoryList, statusList, page, pageSize } = req.body || {}
|
|
let list = dictTypes
|
|
if (dictTypeCodeLike) list = list.filter((d) => d.dictTypeCode.includes(dictTypeCodeLike))
|
|
if (dictTypeNameLike) list = list.filter((d) => d.dictTypeName.includes(dictTypeNameLike))
|
|
if (dictCategoryList?.length) list = list.filter((d) => dictCategoryList.includes(d.dictCategory))
|
|
if (statusList?.length) list = list.filter((d) => statusList.includes(d.status))
|
|
sendOk(res, paginate(list, page, pageSize))
|
|
})
|
|
|
|
router.post('/dict-management/dict-type/create', (req, res) => {
|
|
const { dictCategory, dictTypeCode, dictTypeName, status, remark } = req.body || {}
|
|
if (!dictTypeCode) return sendFail(res, '字典编码不能为空', 400)
|
|
if (!dictTypeName) return sendFail(res, '字典名称不能为空', 400)
|
|
if (!['NORMAL', 'CASCADE'].includes(dictCategory)) return sendFail(res, '字典类别不合法', 400)
|
|
if (dictTypes.some((d) => d.dictTypeCode === dictTypeCode)) return sendFail(res, '字典编码已存在', 400)
|
|
const id = nextId('dictType')
|
|
const entity = {
|
|
id,
|
|
dictCategory,
|
|
dictTypeCode,
|
|
dictTypeName,
|
|
status: status || 'ENABLED',
|
|
remark: remark || '',
|
|
createdAt: new Date().toISOString().slice(0, 19).replace('T', ' ')
|
|
}
|
|
dictTypes.push(entity)
|
|
sendOk(res, entity, '创建成功')
|
|
})
|
|
|
|
router.post('/dict-management/dict-type/update', (req, res) => {
|
|
const { id, dictTypeCode, dictTypeName, status, remark } = req.body || {}
|
|
const entity = dictTypes.find((d) => d.id === id)
|
|
if (!entity) return sendFail(res, '字典类型不存在', 404)
|
|
if (dictTypeCode !== undefined) entity.dictTypeCode = dictTypeCode
|
|
if (dictTypeName !== undefined) entity.dictTypeName = dictTypeName
|
|
if (status !== undefined) entity.status = status
|
|
if (remark !== undefined) entity.remark = remark
|
|
sendOk(res, entity, '更新成功')
|
|
})
|
|
|
|
router.post('/dict-management/dict-type/delete', (req, res) => {
|
|
const { id } = req.body || {}
|
|
const index = dictTypes.findIndex((d) => d.id === id)
|
|
if (index === -1) return sendFail(res, '字典类型不存在', 404)
|
|
const hasItems = dictItems.some((it) => it.dictTypeCode === dictTypes[index].dictTypeCode)
|
|
if (hasItems) return sendFail(res, '该字典类型下还有字典项,不可删除', 400)
|
|
dictTypes.splice(index, 1)
|
|
sendOk(res, true, '删除成功')
|
|
})
|
|
|
|
// ---------------- 动态字典管理:字典项 ----------------
|
|
// 2026-07-31:已按最新 swagger(dict_management 分组)核对确认路径与字段。真实后端的只读接口
|
|
// (dict-items/list、dict-items/tree)实测会返回 id/sortOrder(swagger 未完整声明,以实测为准),
|
|
// 前端(DictItemTree.vue)已据此直接支持对已存在字典项的修改/删除/子级新增,mock 同步在这两个
|
|
// 只读接口的响应里附带 id,贴近真实行为。
|
|
function toOptionVo(it) {
|
|
return { id: it.id, itemValue: it.itemValue, itemLabel: it.itemLabel, sortOrder: it.sortOrder }
|
|
}
|
|
|
|
function buildItemsTree(dictTypeCode) {
|
|
const sorted = dictItems
|
|
.filter((it) => it.dictTypeCode === dictTypeCode && it.status === 'ENABLED')
|
|
.sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0))
|
|
const nodeMap = new Map(
|
|
sorted.map((it) => [it.id, { id: it.id, itemValue: it.itemValue, itemLabel: it.itemLabel, sortOrder: it.sortOrder, children: [] }])
|
|
)
|
|
const idByItemValue = new Map(sorted.map((it) => [it.id, it]))
|
|
const roots = []
|
|
nodeMap.forEach((node, id) => {
|
|
const source = idByItemValue.get(id)
|
|
if (source.parentId && nodeMap.has(source.parentId)) {
|
|
nodeMap.get(source.parentId).children.push(node)
|
|
} else {
|
|
roots.push(node)
|
|
}
|
|
})
|
|
return roots
|
|
}
|
|
|
|
router.post('/dict-management/dict-items/list', (req, res) => {
|
|
const { dictTypeCode } = req.body || {}
|
|
if (!dictTypeCode) return sendFail(res, '字典类型编码不能为空', 400)
|
|
const list = dictItems
|
|
.filter((it) => it.dictTypeCode === dictTypeCode && it.status === 'ENABLED')
|
|
.sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0))
|
|
.map(toOptionVo)
|
|
sendOk(res, list)
|
|
})
|
|
|
|
router.post('/dict-management/dict-items/tree', (req, res) => {
|
|
const { dictTypeCode } = req.body || {}
|
|
if (!dictTypeCode) return sendFail(res, '字典类型编码不能为空', 400)
|
|
sendOk(res, buildItemsTree(dictTypeCode))
|
|
})
|
|
|
|
router.post('/dict-management/dict-items/children', (req, res) => {
|
|
const { dictTypeCode, parentId } = req.body || {}
|
|
if (!dictTypeCode) return sendFail(res, '字典类型编码不能为空', 400)
|
|
const list = dictItems
|
|
.filter((it) => it.dictTypeCode === dictTypeCode && it.status === 'ENABLED' && it.parentId === (parentId ?? null))
|
|
.sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0))
|
|
.map(toOptionVo)
|
|
sendOk(res, list)
|
|
})
|
|
|
|
router.post('/dict-management/dict-item/create', (req, res) => {
|
|
const { dictTypeCode, dictItemBtoList } = req.body || {}
|
|
if (!dictTypeCode) return sendFail(res, '字典类型编码不能为空', 400)
|
|
const item = (dictItemBtoList || [])[0]
|
|
if (!item) return sendFail(res, '字典项数据不能为空', 400)
|
|
const { itemValue, itemLabel, parentId, sortOrder, remark } = item
|
|
if (!itemValue) return sendFail(res, '字典项值不能为空', 400)
|
|
if (!itemLabel) return sendFail(res, '字典项标签不能为空', 400)
|
|
if (dictItems.some((it) => it.dictTypeCode === dictTypeCode && it.itemValue === itemValue)) {
|
|
return sendFail(res, '字典项值已存在', 400)
|
|
}
|
|
const id = nextId('dictItem')
|
|
const entity = {
|
|
id,
|
|
dictTypeCode,
|
|
itemValue,
|
|
itemLabel,
|
|
parentId: parentId ?? null,
|
|
sortOrder: sortOrder ?? 0,
|
|
status: 'ENABLED',
|
|
remark: remark || ''
|
|
}
|
|
dictItems.push(entity)
|
|
sendOk(res, entity, '创建成功')
|
|
})
|
|
|
|
router.post('/dict-management/dict-item/update', (req, res) => {
|
|
const { id, itemValue, itemLabel, parentId, sortOrder, status, remark } = req.body || {}
|
|
const entity = dictItems.find((it) => it.id === id)
|
|
if (!entity) return sendFail(res, '字典项不存在', 404)
|
|
if (itemValue !== undefined) entity.itemValue = itemValue
|
|
if (itemLabel !== undefined) entity.itemLabel = itemLabel
|
|
if (parentId !== undefined) entity.parentId = parentId
|
|
if (sortOrder !== undefined) entity.sortOrder = sortOrder
|
|
if (status !== undefined) entity.status = status
|
|
if (remark !== undefined) entity.remark = remark
|
|
sendOk(res, entity, '更新成功')
|
|
})
|
|
|
|
router.post('/dict-management/dict-item/delete', (req, res) => {
|
|
const { id } = req.body || {}
|
|
const index = dictItems.findIndex((it) => it.id === id)
|
|
if (index === -1) return sendFail(res, '字典项不存在', 404)
|
|
const hasChildren = dictItems.some((it) => it.parentId === id)
|
|
if (hasChildren) return sendFail(res, '存在子级字典项,不可删除', 400)
|
|
dictItems.splice(index, 1)
|
|
sendOk(res, true, '删除成功')
|
|
})
|
|
|
|
export default router
|