提交
This commit is contained in:
1 parent
dacfdc9ff6
commit
f9676f8759
906 files changed
+533306
-12946
No files matched your search
@@ -95,6 +95,46 @@ export function fillAttachmentInfoCache(
|
||||
})
|
||||
}
|
||||
|
||||
export type ContractAttachmentItem = {
|
||||
uid: string
|
||||
name: string
|
||||
ossId?: string
|
||||
url?: string
|
||||
localPreview?: string
|
||||
status: 'uploading' | 'success' | 'error'
|
||||
category: 'single_seal' | 'double_seal' | 'other'
|
||||
}
|
||||
|
||||
/** 合同附件列表 → 保存 API 用的 JSON 字符串 */
|
||||
export function serializeContractAttachments(items: ContractAttachmentItem[]): string {
|
||||
const payload = items
|
||||
.filter((file) => file.status === 'success' && file.ossId)
|
||||
.map((file) => ({
|
||||
ossId: String(file.ossId),
|
||||
category: file.category || 'other'
|
||||
}))
|
||||
return payload.length ? JSON.stringify(payload) : ''
|
||||
}
|
||||
|
||||
/** 合同附件列表 → uploadAttachments 接口 payload */
|
||||
export function mapContractAttachmentsPayload(items: ContractAttachmentItem[]) {
|
||||
return items
|
||||
.filter((file) => file.status === 'success' && file.ossId)
|
||||
.map((file) => ({
|
||||
ossId: String(file.ossId),
|
||||
category: file.category || 'other'
|
||||
}))
|
||||
}
|
||||
|
||||
/** MinIO 相对路径 → 浏览器可访问 URL */
|
||||
export function resolveCrmAttachmentUrl(fileUrl: string): string {
|
||||
const trimmed = String(fileUrl || '').trim()
|
||||
if (!trimmed) return ''
|
||||
if (/^https?:\/\//i.test(trimmed)) return trimmed
|
||||
const base = String(import.meta.env.VITE_MINIO_BASE_URL || '').replace(/\/$/, '')
|
||||
return base ? `${base}/${trimmed.replace(/^\//, '')}` : trimmed
|
||||
}
|
||||
|
||||
export function isCrmImageFile(file: { name?: string; url?: string; ossId?: string }): boolean {
|
||||
const name = file.name || ''
|
||||
if (/\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(name)) return true
|
||||
@@ -102,11 +142,29 @@ export function isCrmImageFile(file: { name?: string; url?: string; ossId?: stri
|
||||
return /\.(jpg|jpeg|png|gif|bmp|webp)(\?|$)/i.test(src)
|
||||
}
|
||||
|
||||
export function isCrmPdfFile(file: { name?: string; url?: string; ossId?: string }): boolean {
|
||||
const name = file.name || ''
|
||||
if (/\.pdf$/i.test(name)) return true
|
||||
const src = file.url || file.ossId || ''
|
||||
return /\.pdf(\?|$)/i.test(src)
|
||||
}
|
||||
|
||||
export function getCrmFileExt(fileName: string): string {
|
||||
const ext = fileName.split('.').pop()?.toUpperCase()
|
||||
return ext || 'FILE'
|
||||
}
|
||||
|
||||
const CRM_ATTACHMENT_CATEGORY_LABELS: Record<string, string> = {
|
||||
single_seal: '单章附件',
|
||||
double_seal: '双章附件',
|
||||
other: '其他附件'
|
||||
}
|
||||
|
||||
/** 附件分类 → 展示文案 */
|
||||
export function getCrmAttachmentCategoryLabel(category?: string): string {
|
||||
return CRM_ATTACHMENT_CATEGORY_LABELS[category || 'other'] || CRM_ATTACHMENT_CATEGORY_LABELS.other
|
||||
}
|
||||
|
||||
/** 下载 CRM 附件(fileUrl / ossId 均为 MinIO 路径或完整 URL) */
|
||||
export async function downloadCrmAttachment(file: {
|
||||
ossId?: string
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/** CRM 附件上传 bizType(与原 RuoYi /resource/oss/upload 一致) */
|
||||
export const CRM_UPLOAD_BIZ_TYPE = {
|
||||
CONTRACT_ATTACHMENT: 'crm_contract_attachment',
|
||||
CONTRACT_PRICE_LETTER: 'crm_contract_price_letter',
|
||||
CONTRACT_FILE: 'crm_contract_file',
|
||||
QUOTE_ATTACHMENT: 'crm_quote_attachment'
|
||||
} as const
|
||||
|
||||
export type CrmUploadBizType = (typeof CRM_UPLOAD_BIZ_TYPE)[keyof typeof CRM_UPLOAD_BIZ_TYPE]
|
||||
|
||||
/** 构建门户统一上传 FormData(file + bizType,folder 可选覆盖) */
|
||||
export function buildAttachmentUploadFormData(
|
||||
file: File,
|
||||
options: { bizType: CrmUploadBizType | string; folder?: string }
|
||||
): FormData {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
formData.append('bizType', options.bizType)
|
||||
if (options.folder) {
|
||||
formData.append('folder', options.folder)
|
||||
}
|
||||
return formData
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 全局包装 ElTag:默认插槽无有效内容时不渲染,避免空值时出现带背景色的空 tag。
|
||||
* 通过 vite Components 自定义 resolver 替换自动导入的 ElTag。
|
||||
*/
|
||||
import { ElTag } from 'element-plus'
|
||||
import { Comment, Text, defineComponent, h, type VNode, type VNodeArrayChildren } from 'vue'
|
||||
|
||||
function hasVisibleDefaultContent(vnodes: VNode[] | undefined): boolean {
|
||||
if (!vnodes?.length) return false
|
||||
|
||||
const walk = (nodes: VNodeArrayChildren | undefined): boolean => {
|
||||
if (!nodes) return false
|
||||
for (const node of nodes) {
|
||||
if (node == null || node === false) continue
|
||||
if (typeof node === 'string' || typeof node === 'number') {
|
||||
if (String(node).trim()) return true
|
||||
continue
|
||||
}
|
||||
const vnode = node as VNode
|
||||
if (vnode.type === Comment) continue
|
||||
if (vnode.type === Text) {
|
||||
if (String(vnode.children ?? '').trim()) return true
|
||||
continue
|
||||
}
|
||||
if (vnode.type) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return walk(vnodes)
|
||||
}
|
||||
|
||||
const EmptyAwareElTag = defineComponent({
|
||||
name: 'ElTag',
|
||||
inheritAttrs: false,
|
||||
props: ElTag.props,
|
||||
setup(props, { slots, attrs }) {
|
||||
return () => {
|
||||
if (!hasVisibleDefaultContent(slots.default?.())) {
|
||||
return null
|
||||
}
|
||||
return h(ElTag, { ...props, ...attrs }, slots)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default EmptyAwareElTag
|
||||
Reference in new issue
Block a user