|
|
@@ -0,0 +1,160 @@
|
|
|
+import { fetchDeptTree } from '@/api/admin'
|
|
|
+import { isDeptValueItem, type OaDeptValueItem } from '@/utils/oa-dept-value'
|
|
|
+import { isPersonValueItem, type OaPersonValueItem } from '@/utils/oa-person-value'
|
|
|
+import { buildPathLabelMapFromTreeRoots } from '@/utils/tree-path'
|
|
|
+
|
|
|
+export type OwnerUserSnapshot = {
|
|
|
+ id?: string
|
|
|
+ userId?: string
|
|
|
+ realName?: string
|
|
|
+ userName?: string
|
|
|
+ username?: string
|
|
|
+ regionId?: string
|
|
|
+ deptId?: string
|
|
|
+ regionName?: string
|
|
|
+ deptName?: string
|
|
|
+}
|
|
|
+
|
|
|
+function walkRules(rules: unknown[], out: Record<string, any>[]) {
|
|
|
+ for (const r of rules) {
|
|
|
+ if (!r || typeof r !== 'object') continue
|
|
|
+ const rule = r as Record<string, any>
|
|
|
+ out.push(rule)
|
|
|
+ const children = rule.children || rule.props?.rule || []
|
|
|
+ if (Array.isArray(children)) walkRules(children, out)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function flattenRules(schemaOrRules: unknown): Record<string, any>[] {
|
|
|
+ if (Array.isArray(schemaOrRules)) {
|
|
|
+ const out: Record<string, any>[] = []
|
|
|
+ walkRules(schemaOrRules, out)
|
|
|
+ return out
|
|
|
+ }
|
|
|
+ if (schemaOrRules && typeof schemaOrRules === 'object') {
|
|
|
+ const root = schemaOrRules as any
|
|
|
+ const rules = root.rule || root.rules || []
|
|
|
+ if (Array.isArray(rules)) {
|
|
|
+ const out: Record<string, any>[] = []
|
|
|
+ walkRules(rules, out)
|
|
|
+ return out
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return []
|
|
|
+}
|
|
|
+
|
|
|
+function isEmptyOwnerValue(raw: unknown): boolean {
|
|
|
+ if (raw == null || raw === '') return true
|
|
|
+ if (Array.isArray(raw)) return raw.length === 0
|
|
|
+ if (typeof raw === 'object') {
|
|
|
+ const o = raw as Record<string, unknown>
|
|
|
+ return !String(o.id || '').trim()
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
+export function buildCurrentOwnerPerson(user: OwnerUserSnapshot | null | undefined): OaPersonValueItem | null {
|
|
|
+ if (!user) return null
|
|
|
+ const id = String(user.id || user.userId || '').trim()
|
|
|
+ if (!id) return null
|
|
|
+ const name = String(user.realName || user.userName || user.username || '').trim() || id
|
|
|
+ return { id, name }
|
|
|
+}
|
|
|
+
|
|
|
+export function buildCurrentOwnerDeptSync(
|
|
|
+ user: OwnerUserSnapshot | null | undefined
|
|
|
+): OaDeptValueItem | null {
|
|
|
+ if (!user) return null
|
|
|
+ const id = String(user.regionId || user.deptId || '').trim()
|
|
|
+ if (!id) return null
|
|
|
+ const name = String(user.regionName || user.deptName || '').trim() || id
|
|
|
+ return { id, name }
|
|
|
+}
|
|
|
+
|
|
|
+/** 用部门树解析全路径名称;失败则回退 id / 登录态名称 */
|
|
|
+export async function resolveCurrentOwnerDept(
|
|
|
+ user: OwnerUserSnapshot | null | undefined
|
|
|
+): Promise<OaDeptValueItem | null> {
|
|
|
+ const base = buildCurrentOwnerDeptSync(user)
|
|
|
+ if (!base) return null
|
|
|
+ try {
|
|
|
+ const tree = (await fetchDeptTree()) || []
|
|
|
+ const map = buildPathLabelMapFromTreeRoots(tree as any, { nameKey: 'deptName' })
|
|
|
+ const path = map.get(base.id)
|
|
|
+ if (path) return { id: base.id, name: path }
|
|
|
+ } catch {
|
|
|
+ /* 无部门树权限时仍用 id/名称回退 */
|
|
|
+ }
|
|
|
+ return base
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 发起页:写入当前登录人 / 主部门。
|
|
|
+ * - allowModify 为假:始终覆盖为当前用户(防展示旧值 / 复制发起)
|
|
|
+ * - allowModify 为真:仅空字段补默认
|
|
|
+ */
|
|
|
+export async function applyOwnerFieldDefaults(
|
|
|
+ schemaOrRules: unknown,
|
|
|
+ formData: Record<string, any>,
|
|
|
+ user: OwnerUserSnapshot | null | undefined
|
|
|
+): Promise<Record<string, any>> {
|
|
|
+ const rules = flattenRules(schemaOrRules)
|
|
|
+ const hasPerson = rules.some((r) => String(r.type || '') === 'ownerPerson')
|
|
|
+ const hasDept = rules.some((r) => String(r.type || '') === 'ownerDept')
|
|
|
+ if (!hasPerson && !hasDept) return { ...formData }
|
|
|
+
|
|
|
+ const person = hasPerson ? buildCurrentOwnerPerson(user) : null
|
|
|
+ const dept = hasDept ? await resolveCurrentOwnerDept(user) : null
|
|
|
+ const next = { ...formData }
|
|
|
+
|
|
|
+ for (const rule of rules) {
|
|
|
+ const type = String(rule.type || '')
|
|
|
+ const field = String(rule.field || rule.name || '').trim()
|
|
|
+ if (!field) continue
|
|
|
+ const allowModify = rule.props?.allowModify === true
|
|
|
+ if (type === 'ownerPerson' && person) {
|
|
|
+ if (!allowModify || isEmptyOwnerValue(next[field])) {
|
|
|
+ next[field] = person
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (type === 'ownerDept' && dept) {
|
|
|
+ if (!allowModify || isEmptyOwnerValue(next[field])) {
|
|
|
+ next[field] = dept
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return next
|
|
|
+}
|
|
|
+
|
|
|
+/** 确保 props.allowModify 有明确布尔(缺省 false) */
|
|
|
+export function ensureOwnerFieldRuleProps(rules: unknown): any[] {
|
|
|
+ if (!Array.isArray(rules)) return []
|
|
|
+ return rules.map((raw) => {
|
|
|
+ if (!raw || typeof raw !== 'object') return raw
|
|
|
+ const rule = { ...(raw as any) }
|
|
|
+ const type = String(rule.type || '')
|
|
|
+ if (type === 'ownerPerson' || type === 'ownerDept') {
|
|
|
+ const props = { ...(rule.props || {}) }
|
|
|
+ if (props.allowModify !== true) props.allowModify = false
|
|
|
+ rule.props = props
|
|
|
+ }
|
|
|
+ if (Array.isArray(rule.children)) {
|
|
|
+ rule.children = ensureOwnerFieldRuleProps(rule.children)
|
|
|
+ }
|
|
|
+ if (rule.props && Array.isArray(rule.props.rule)) {
|
|
|
+ rule.props = {
|
|
|
+ ...rule.props,
|
|
|
+ rule: ensureOwnerFieldRuleProps(rule.props.rule)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return rule
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+export function isOwnerPersonValue(v: unknown): v is OaPersonValueItem {
|
|
|
+ return isPersonValueItem(v)
|
|
|
+}
|
|
|
+
|
|
|
+export function isOwnerDeptValue(v: unknown): v is OaDeptValueItem {
|
|
|
+ return isDeptValueItem(v)
|
|
|
+}
|