/** * 确保生产 DMS 有 shba_perm 栏目(职务菜单/按钮权限)。 * 凭据默认与 src/api/dmsAuth.ts 相同。栏目已存在则灌默认四职务(若为空)。 * addModel 必须从 shba_org_model 整表克隆并重排 index,不能自造字段结构。 */ import { DMS_CLIENT_ID, DMS_GATEWAY, DMS_PASSWORD, DMS_USER } from './dms-cred.mjs' const gateway = DMS_GATEWAY let token = '' async function call(urlPath, fields = {}, method = 'POST') { const body = new URLSearchParams() for (const [k, v] of Object.entries(fields)) body.set(k, String(v)) const headers = { 'Content-Type': 'application/x-www-form-urlencoded' } if (token) headers.Token = token const res = await fetch(urlPath.startsWith('http') ? urlPath : `${gateway}${urlPath}`, { method, headers, body }) return res.json() } function walk(nodes, map = {}) { for (const n of nodes || []) { if (n.tag) map[n.tag] = n walk(n.columnList, map) } return map } function extra(name, alias, seq, describe = alias) { return { alias, customType: '', defaultValue: '', describe, frontType: seq === 1 ? 'varchar' : 'text', must: false, name, searchType: '2', sequence: seq, index: seq, showParam: 'name,alias,desc,type,front_type,must,default_value', type: 'text', } } function parseFieldList(raw) { const obj = typeof raw === 'string' ? JSON.parse(raw) : (raw || {}) const out = {} for (const [k, v] of Object.entries(obj)) out[k] = typeof v === 'string' ? JSON.parse(v) : v return out } function cloneFieldList(parsed) { const cloned = {} Object.keys(parsed).forEach((key, i) => { const src = parsed[key] || {} cloned[key] = { ...src, name: src.name || key, index: i } }) return cloned } function asModels(raw) { if (Array.isArray(raw)) return raw if (raw?.data && Array.isArray(raw.data)) return raw.data return [] } const login = await call(`${gateway}/proxy_oauth/user/login`, { userName: DMS_USER, password: DMS_PASSWORD, clientId: DMS_CLIENT_ID, }) if (login.code !== 200 || !login.message) { console.error('登录失败', login.message || login) process.exit(1) } token = login.message const author = login.content || {} const cols = walk((await call('/proxy_dms/column/getColumnList', {})).content) let col = cols.shba_perm if (!col?.id) { const models = asModels((await call('/proxy_dms/model/getModelList', { type: 1 })).content) let model = models.find((m) => m.modelName === 'shba_perm_model') if (!model) { const org = models.find((m) => m.modelName === 'shba_org_model') if (!org?.id) { console.error('找不到 shba_org_model,无法克隆') process.exit(1) } const detail = await call('/proxy_dms/model/getModelById', { modelId: org.id }) const cloned = cloneFieldList(parseFieldList(detail.content.fieldList)) const created = await call('/proxy_dms/model/addModel', { modelName: 'shba_perm_model', modelAlias: '职务权限', pageSize: 20, sortField: '[]', searchField: '[]', fieldList: JSON.stringify(cloned), type: 1, authorName: author.username || 'demo', authorId: author.id || 98, }, 'PUT') console.log('addModel', created.code, created.message, created.content && created.content.id) if (created.code !== 200 || !created.content?.id) { console.error('addModel 失败', JSON.stringify(created).slice(0, 500)) process.exit(1) } model = { id: created.content.id } } else { console.log('reuse model', model.id) } const parent = cols.shba_master || cols.shba const added = await call('/proxy_dms/column/addColumn', { tag: 'shba_perm', title: '职务权限', content: '按职务配置后台菜单和按钮。', parentId: parent.id, type: 1, state: 0, level: 2, modelId: model.id, authorName: author.username || 'demo', authorId: author.id || 98, }, 'PUT') console.log('column', added.code, added.message) if (added.code !== 200) { console.error('addColumn 失败', JSON.stringify(added).slice(0, 500)) process.exit(1) } const again = walk((await call('/proxy_dms/column/getColumnList', {})).content) col = again.shba_perm } if (!col?.id || !col.modelId) { console.error('栏目未就绪', col) process.exit(1) } console.log('shba_perm', col.id, col.modelName, 'model', col.modelId) const detail = await call('/proxy_dms/model/getModelById', { modelId: col.modelId }) const fieldList = parseFieldList(detail.content.fieldList) const addfieldList = {} const specs = [extra('role', '职务', 1, 'hq/branch/site/guard'), extra('menus', '菜单权限', 2, '菜单 key JSON'), extra('actions', '按钮权限', 3, '操作 key JSON')] for (const spec of specs) { const colName = `c_${spec.name}` if (fieldList[colName]) continue fieldList[colName] = extra(colName, spec.alias, spec.sequence, spec.describe) addfieldList[spec.name] = spec } if (Object.keys(addfieldList).length) { const upd = await call('/proxy_dms/model/updateFieldList', { modelId: col.modelId, fieldList: JSON.stringify(fieldList), addfieldList: JSON.stringify(addfieldList), delfieldList: '{}', updatefieldList: '{}', }) console.log('fields', upd.code, upd.message, Object.keys(addfieldList).join(',')) } else { console.log('fields already', Object.keys(fieldList).filter((k) => k.startsWith('c_')).join(',')) } const listed = await call('/proxy_dms/content/selectContentList', { columnId: col.id, search: '[]', orderBy: '[{"field":"update_time","orderByType":2}]', page: 0, pageSize: 50, }) const rows = listed.content?.data || [] console.log('existing perms', rows.length, rows.map((r) => `${r.content}:${r.c_role}`).join(' | ')) const seeds = [ { content: 'perm-hq', title: '人防管理员', c_role: 'hq', c_menus: '["*"]', c_actions: '["*"]' }, { content: 'perm-branch', title: '分公司经理', c_role: 'branch', c_menus: JSON.stringify(['workbench','master.people','master.sites','master.contracts','master.train','duty.schedule','duty.attend','duty.ot','duty.split','duty.ident','field','collab.notice','collab.event','collab.alarm','collab.perform','collab.alert','finance.ledger','finance.board','finance.staffing','finance.supplier']), c_actions: JSON.stringify(['person.create','person.edit','person.delete','person.import','site.create','site.edit','site.delete','contract.create','contract.edit','contract.delete','train.create','train.edit','train.delete','schedule.edit','attend.edit','attend.delete','attend.export','split.export','ident.export','field.punch','notice.send','notice.read','notice.delete','notice.call','event.create','event.flow','event.delete','alarm.trigger','invert.create','invert.delete','alert.toggle','finance.edit','finance.lock','staffing.edit','supplier.pay']) }, { content: 'perm-site', title: '驻点督导', c_role: 'site', c_menus: JSON.stringify(['workbench','master.people','master.sites','master.contracts','master.train','duty.schedule','duty.attend','duty.ot','duty.split','duty.ident','field','collab.notice','collab.event','collab.alarm','collab.perform','collab.alert']), c_actions: JSON.stringify(['person.create','person.edit','schedule.edit','attend.edit','attend.export','notice.send','notice.read','notice.call','event.create','event.flow','alarm.trigger','alert.toggle','field.punch']) }, { content: 'perm-guard', title: '保安队员', c_role: 'guard', c_menus: '[]', c_actions: '[]' }, ] const seen = new Set() for (const row of rows) { const key = String(row.c_role || row.content || '') if (!key) continue if (seen.has(key)) { const gone = await call('/proxy_dms/content/updateAudit', { columnId: col.id, id: row.id, state: 4, auditorName: 'demo', }) console.log('dedupe', row.content, gone.code, gone.message) } else { seen.add(key) } } const have = seen for (const seed of seeds) { if (have.has(seed.content) || have.has(seed.c_role)) { console.log('skip', seed.content) continue } const added = await call('/proxy_dms/content/addContent', { columnId: col.id, modelId: col.modelId, content: JSON.stringify(seed), }) console.log('add', seed.content, added.code, added.message) }