This commit is contained in:
zlwu committed 2026-07-21 15:23:59 +08:00
1 parent 417d6c9c51
commit c8fe0cdc20
102 files changed
+19847 -12224

No files matched your search

+29 -4
View File
@@ -238,18 +238,42 @@ function buildFlowItems(detail: any): OaPrintFlowItem[] {
ccBuf = null
}
const peopleNames = (p: any): string[] => {
const people = Array.isArray(p?.people) ? p.people : []
const fromPeople = people
.map((x: any) => {
const n = String(x?.nickName || x?.id || '').trim()
if (!n) return ''
const st = String(x?.status || '')
if (st === 'approved') return `${n}(已同意)`
if (st === 'rejected') return `${n}(已拒绝)`
if (st === 'returned') return `${n}(已打回)`
if (st === 'pending' || st === 'running') return `${n}(待处理)`
if (st === 'done') return `${n}(无需处理)`
return n
})
.filter(Boolean)
if (fromPeople.length) return fromPeople
const name = String(p.assigneeUserName || p.assigneeUserId || '').trim()
return name ? [name] : []
}
for (const p of list) {
const kind = String(p.kind || '')
const taskType = String(p.taskType || '')
const title = String(p.title || '-').trim()
const name = String(p.assigneeUserName || p.assigneeUserId || '').trim()
const names = peopleNames(p)
const name = names.join(',')
const ts = String(p.timestamp || '').trim()
const comment = String(p.commentText || '').trim()
const st = statusText(String(p.status || ''))
const signMode = String(p.signMode || '')
const signLabel = signMode === 'and' ? '会签' : signMode === 'or' ? '或签' : ''
if (taskType === 'cc') {
if (!ccBuf) ccBuf = { names: [], ts }
if (name) ccBuf.names.push(name)
if (names.length) ccBuf.names.push(...names.map((n) => n.replace(/\(.*?\)\s*$/, '')))
else if (name) ccBuf.names.push(name)
if (ts) ccBuf.ts = ts
continue
}
@@ -277,9 +301,10 @@ function buildFlowItems(detail: any): OaPrintFlowItem[] {
})
continue
}
// task
// task(或签/会签同节点多人已合并)
const head = signLabel ? `【${title}·${signLabel}】` : `【${title}】`
items.push({
left: name ? `【${title}】 ${name} ${st}` : `【${title}】 ${st}`,
left: name ? `${head} ${name} ${st}` : `${head} ${st}`,
right: ts,
comment: comment || undefined
})
@@ -0,0 +1,164 @@
/**
* FormCreate 运行时补丁:
* - 内置 upload 默认 action 为「/」,会 POST 到前端原点导致 404;接管为附件上传 API
* - 运行时注册 FcRow(flex ._fd-row),间距与铺满由 oa-fc-runtime.scss 处理
*/
import { ElMessage } from 'element-plus'
import { fetchUploadAttachment } from '@/api/business'
import { attachmentFullUrl } from '@/composables/useAttachmentActions'
import OaFcRow from '@/components/oa-approval/OaFcRow.vue'
type FcFetchOptions = {
source?: string
file?: File
filename?: string
data?: Record<string, unknown>
action?: string
onSuccess?: (res: unknown) => void
onError?: (err: unknown) => void
[key: string]: unknown
}
const FLAG = '__oaUploadConfigured'
const UPLOAD_TYPES = new Set(['upload', 'fcUpload'])
/** 与业务表单 `.form-grid-2` 横向间距对齐(顶层 option.row.gutter / CSS --oa-fc-gutter) */
export const OA_FC_DEFAULT_GUTTER = 20
/** 从上传接口响应中取出可回显的 url(兼容 FormCreate 默认 onSuccess) */
export function resolveUploadResponseUrl(res: any): string {
const raw = String(
res?.data?.url || res?.data?.fileUrl || res?.fileUrl || res?.url || ''
).trim()
if (!raw) return ''
return attachmentFullUrl(raw) || raw
}
function ensureUploadRule(rule: any) {
if (!UPLOAD_TYPES.has(String(rule.type || ''))) return
const props = { ...(rule.props || {}) }
if (!props.action || props.action === '/') {
props.action = '#'
}
const prevSuccess = props.onSuccess
// `$FNX:...` 须留给 FormCreate 编译;替换成函数会丢掉官方 file.url = res.data.url
if (typeof prevSuccess === 'string' && prevSuccess.includes('$FNX')) {
// keep
} else if (typeof prevSuccess === 'function') {
props.onSuccess = (res: any, file: any) => {
try {
prevSuccess(res, file)
} catch {
/* ignore */
}
const url = resolveUploadResponseUrl(res)
// Element Plus 选文件时已写入 blob: URL,必须强制覆盖
if (url && file) {
file.url = url
}
}
} else if (!prevSuccess) {
props.onSuccess = (res: any, file: any) => {
const url = resolveUploadResponseUrl(res)
if (url && file) {
file.url = url
}
}
}
rule.props = props
}
/**
* 运行时补齐 FormCreate rule(upload action / onSuccess)
*/
export function ensureOaUploadRuleProps(rules: unknown): any[] {
if (!Array.isArray(rules)) return []
return rules.map((raw) => {
if (!raw || typeof raw !== 'object') return raw
const rule: any = { ...(raw as object) }
ensureUploadRule(rule)
if (Array.isArray(rule.children)) {
rule.children = ensureOaUploadRuleProps(rule.children)
}
if (Array.isArray(rule.props?.rule)) {
rule.props = {
...rule.props,
rule: ensureOaUploadRuleProps(rule.props.rule)
}
}
if (Array.isArray(rule.control)) {
rule.control = rule.control.map((c: any) => {
if (!c || typeof c !== 'object') return c
if (Array.isArray(c.rule)) {
return { ...c, rule: ensureOaUploadRuleProps(c.rule) }
}
return c
})
}
return rule
})
}
export function setupFormCreateUpload(formCreate: {
fetch?: (opts: FcFetchOptions) => void
component?: (name: string, component: unknown) => void
}) {
if (!formCreate || (formCreate as any)[FLAG]) return
// 主应用 formCreate 默认未挂设计器 FcRow;用 flex 行保证栅格铺满,间距走 CSS
if (typeof formCreate.component === 'function') {
formCreate.component('fcRow', OaFcRow)
formCreate.component('FcRow', OaFcRow)
}
const prevFetch = formCreate.fetch
formCreate.fetch = (options: FcFetchOptions) => {
const isUpload = options?.source === 'upload' || !!options?.file
if (!isUpload) {
if (typeof prevFetch === 'function') {
return prevFetch(options)
}
return
}
void (async () => {
try {
const file = options.file
if (!file) {
throw new Error('未选择文件')
}
const fd = new FormData()
fd.append('file', file)
fd.append('folder', 'oa-approval')
const extra = options.data
if (extra && typeof extra === 'object') {
Object.entries(extra).forEach(([k, v]) => {
if (v != null && k !== 'file' && k !== 'folder') {
fd.append(k, String(v))
}
})
}
const res: any = await fetchUploadAttachment(fd)
const rawUrl = String(res?.fileUrl || res?.data?.fileUrl || '').trim()
if (!rawUrl) {
throw new Error('上传失败:未返回文件地址')
}
// 预览用完整 URL;设计器默认 onSuccess 为 file.url = res.data.url
const url = attachmentFullUrl(rawUrl) || rawUrl
options.onSuccess?.({
data: { url, fileUrl: rawUrl },
fileUrl: rawUrl,
url
})
} catch (e) {
const msg = e instanceof Error ? e.message : '上传失败'
ElMessage.error(msg)
options.onError?.(e)
}
})()
}
;(formCreate as any)[FLAG] = true
}