diff --git a/web/apps/web-ele/package.json b/web/apps/web-ele/package.json index 11b8a26..9e587e1 100644 --- a/web/apps/web-ele/package.json +++ b/web/apps/web-ele/package.json @@ -69,10 +69,8 @@ "element-plus": "catalog:", "jsbarcode": "^3.12.3", "nanoid": "^5.1.7", - "perfect-freehand": "^1.2.3", "pinia": "catalog:", "qrcode": "^1.5.4", - "roughjs": "^4.6.6", "uuid": "^13.0.0", "vue": "catalog:", "vue-qrcode-reader": "^5.7.3", diff --git a/web/apps/web-ele/src/api/smart-table.ts b/web/apps/web-ele/src/api/smart-table.ts deleted file mode 100644 index 887c15a..0000000 --- a/web/apps/web-ele/src/api/smart-table.ts +++ /dev/null @@ -1,675 +0,0 @@ -import { requestClient } from '#/api/request'; - -const BASE = '/api/smart-table'; - -// ==================== Types ==================== - -export interface SmartTableItem { - id: string; - name: string; - icon: string; - type?: string; - parent_id?: string | null; - sort?: number; - description?: string; - active_view_id?: string; - sys_create_datetime?: string; - sys_update_datetime?: string; -} - -export interface SmartFieldItem { - id: string; - table_id: string; - name: string; - type: string; - width: number; - visible: boolean; - required: boolean; - description?: string; - config: Record; - sort: number; - sys_create_datetime?: string; -} - -export interface SmartRecordItem { - id: string; - table_id: string; - values: Record; - sys_create_datetime?: string; - sys_update_datetime?: string; - sys_creator_id?: string; - sys_modifier_id?: string; -} - -export interface SmartViewItem { - id: string; - table_id: string; - name: string; - type: string; - config: Record; - sort: number; - sys_create_datetime?: string; -} - -export interface SmartTableFull extends SmartTableItem { - type?: string; - content?: any; - fields: SmartFieldItem[]; - records: SmartRecordItem[]; - views: SmartViewItem[]; - record_total: number; - next_cursor: string | null; - has_more: boolean; - sys_creator_id?: string; - creator_name?: string; - creator_avatar?: string; -} - -export interface CursorPaginatedRecords { - items: SmartRecordItem[]; - total: number; - next_cursor: string | null; - has_more: boolean; -} - -export interface RecordFilterParam { - field_id: string; - operator: string; - value?: any; -} - -export interface RecordSortParam { - field_id: string; - direction: 'asc' | 'desc'; -} - -export interface RecordQueryParam { - filters?: RecordFilterParam[]; - filter_logic?: 'and' | 'or'; - sorts?: RecordSortParam[]; - search?: string; - search_field_ids?: string[]; - group_field_id?: string; - cursor?: string | null; - limit?: number; -} - -export interface RecordGroupItem { - key: string; - label: string; - records: SmartRecordItem[]; -} - -export interface GroupedRecordsResponse { - groups: RecordGroupItem[]; - total: number; -} - -// ==================== Table API ==================== - -export function getTableListApi(wikiSpaceId?: string | null) { - const params: Record = {}; - if (wikiSpaceId) params.wiki_space_id = wikiSpaceId; - return requestClient.get(`${BASE}/tables`, { params }); -} - -export function getTableFullApi( - tableId: string, - opts?: { filters?: RecordFilterParam[]; sorts?: RecordSortParam[]; search?: string; filter_logic?: string }, -) { - const params: Record = {}; - if (opts?.filters?.length) params.filters = JSON.stringify(opts.filters); - if (opts?.sorts?.length) params.sorts = JSON.stringify(opts.sorts); - if (opts?.search) params.search = opts.search; - if (opts?.filter_logic) params.filter_logic = opts.filter_logic; - return requestClient.get(`${BASE}/tables/${tableId}/full`, { params }); -} - -export function createTableApi(data: { name: string; icon?: string; description?: string; type?: string; content?: any; parent_id?: string | null; wiki_space_id?: string | null }) { - return requestClient.post(`${BASE}/tables`, data); -} - -export function updateTableApi(tableId: string, data: Partial) { - return requestClient.put(`${BASE}/tables/${tableId}`, data); -} - -export function updateDocumentContentApi(tableId: string, content: any) { - return requestClient.patch(`${BASE}/tables/${tableId}/content`, { content }); -} - -export function exportDocumentPdfApi(tableId: string, html: string, title: string) { - return requestClient.post(`${BASE}/tables/${tableId}/export-pdf`, { html, title }, { - responseType: 'blob', - }); -} - -export function deleteTableApi(tableId: string) { - return requestClient.delete(`${BASE}/tables/${tableId}`); -} - -export function moveTableApi(tableId: string, parentId: string | null, afterId?: string | null) { - return requestClient.put(`${BASE}/tables/${tableId}/move`, { - parent_id: parentId, - after_id: afterId ?? null, - }); -} - -// ==================== Field API ==================== - -export function getFieldListApi(tableId: string) { - return requestClient.get(`${BASE}/tables/${tableId}/fields`); -} - -export function createFieldApi(tableId: string, data: Omit) { - return requestClient.post(`${BASE}/tables/${tableId}/fields`, data); -} - -export function updateFieldApi(fieldId: string, data: Partial) { - return requestClient.put(`${BASE}/fields/${fieldId}`, data); -} - -export function deleteFieldApi(fieldId: string) { - return requestClient.delete(`${BASE}/fields/${fieldId}`); -} - -export function reorderFieldsApi(tableId: string, fieldIds: string[]) { - return requestClient.put(`${BASE}/tables/${tableId}/fields/reorder`, { field_ids: fieldIds }); -} - -// ==================== Record API ==================== - -export function getRecordListApi( - tableId: string, - cursor?: string | null, - limit = 200, - opts?: { filters?: RecordFilterParam[]; sorts?: RecordSortParam[]; search?: string; filter_logic?: string }, -) { - const params: Record = { cursor: cursor ?? undefined, limit }; - if (opts?.filters?.length) params.filters = JSON.stringify(opts.filters); - if (opts?.sorts?.length) params.sorts = JSON.stringify(opts.sorts); - if (opts?.search) params.search = opts.search; - if (opts?.filter_logic) params.filter_logic = opts.filter_logic; - return requestClient.get( - `${BASE}/tables/${tableId}/records`, - { params }, - ); -} - -export function queryRecordsApi(tableId: string, query: RecordQueryParam) { - return requestClient.post( - `${BASE}/tables/${tableId}/records/query`, - query, - ); -} - -export function reorderRecordsApi(tableId: string, recordIds: string[]) { - return requestClient.put(`${BASE}/tables/${tableId}/records/reorder`, { record_ids: recordIds }); -} - -export function createRecordApi(tableId: string, values: Record = {}) { - return requestClient.post(`${BASE}/tables/${tableId}/records`, { table_id: tableId, values }); -} - -export function updateRecordApi(recordId: string, values: Record) { - return requestClient.put(`${BASE}/records/${recordId}`, { values }); -} - -export function updateCellApi(recordId: string, fieldId: string, value: any) { - return requestClient.patch(`${BASE}/records/${recordId}/cells`, { - field_id: fieldId, - value, - }); -} - -export function batchUpdateCellsApi(recordId: string, cells: Record) { - return requestClient.patch(`${BASE}/records/${recordId}/cells/batch`, { cells }); -} - -export function batchUpdateMultiRecordCellsApi( - tableId: string, - updates: Array<{ record_id: string; cells: Record }>, -) { - return requestClient.patch(`${BASE}/tables/${tableId}/records/batch-cells`, { updates }); -} - -export function deleteRecordApi(recordId: string) { - return requestClient.delete(`${BASE}/records/${recordId}`); -} - -export function batchDeleteRecordsApi(tableId: string, ids: string[]) { - return requestClient.post(`${BASE}/tables/${tableId}/records/batch-delete`, { ids }); -} - -// ==================== Trash / Recycle Bin ==================== - -export interface TrashRecordItem { - id: string; - table_id: string; - values: Record; - sys_create_datetime?: string; - sys_update_datetime?: string; - sys_creator_id?: string; -} - -export function getTrashRecordsApi(tableId: string, page = 1, pageSize = 50) { - return requestClient.get<{ items: TrashRecordItem[]; total: number }>( - `${BASE}/tables/${tableId}/trash`, - { params: { page, page_size: pageSize } }, - ); -} - -export function restoreTrashRecordsApi(tableId: string, ids: string[]) { - return requestClient.post(`${BASE}/tables/${tableId}/trash/restore`, { ids }); -} - -export function permanentDeleteTrashRecordApi(tableId: string, recordId: string) { - return requestClient.delete(`${BASE}/tables/${tableId}/trash/${recordId}`); -} - -export function emptyTrashApi(tableId: string) { - return requestClient.delete(`${BASE}/tables/${tableId}/trash`); -} - -export function exportTableApi(tableId: string, format: 'csv' | 'xlsx' = 'csv') { - return requestClient.get(`${BASE}/tables/${tableId}/export`, { - params: { format }, - responseType: 'blob', - }); -} - -export function importTableApi(tableId: string, file: File) { - const formData = new FormData(); - formData.append('file', file); - return requestClient.post(`${BASE}/tables/${tableId}/import`, formData, { - headers: { 'Content-Type': 'multipart/form-data' }, - }); -} - -export interface RecordSearchResultItem { - id: string; - title: string; -} - -export function searchRecordsApi(tableId: string, keyword: string = '', limit: number = 20) { - return requestClient.post( - `${BASE}/tables/${tableId}/records/search`, - { keyword, limit }, - ); -} - -// ==================== Summary API ==================== - -export interface SummaryResult { - summaries: Record; - total_count: number; -} - -export function getSummaryApi( - tableId: string, - data: { - aggregations: Record; - filters?: RecordFilterParam[]; - filter_logic?: string; - search?: string; - }, -) { - return requestClient.post(`${BASE}/tables/${tableId}/summary`, data); -} - -// ==================== Comment API ==================== - -export interface CommentItem { - id: string; - record_id: string; - user_id: string; - content: string; - mentions: string[]; - parent_id: string | null; - sys_create_datetime?: string; - sys_update_datetime?: string; - user_name?: string; - user_avatar?: string; - replies: CommentItem[]; -} - -export function getCommentsApi(recordId: string) { - return requestClient.get(`${BASE}/records/${recordId}/comments`); -} - -export function createCommentApi(recordId: string, data: { content: string; mentions?: string[]; parent_id?: string }) { - return requestClient.post(`${BASE}/records/${recordId}/comments`, data); -} - -export function updateCommentApi(commentId: string, data: { content: string; mentions?: string[] }) { - return requestClient.put(`${BASE}/comments/${commentId}`, data); -} - -export function deleteCommentApi(commentId: string) { - return requestClient.delete(`${BASE}/comments/${commentId}`); -} - -// ==================== View API ==================== - -export function getViewListApi(tableId: string) { - return requestClient.get(`${BASE}/tables/${tableId}/views`); -} - -export function createViewApi(tableId: string, data: { name: string; type: string; config?: Record }) { - return requestClient.post(`${BASE}/tables/${tableId}/views`, { ...data, table_id: tableId }); -} - -export function updateViewApi(viewId: string, data: Partial) { - return requestClient.put(`${BASE}/views/${viewId}`, data); -} - -export function deleteViewApi(viewId: string) { - return requestClient.delete(`${BASE}/views/${viewId}`); -} - -// ==================== Permission API ==================== - -export interface MyPermission { - role_type: string; - role_name: string; - capabilities: Record; - field_permissions: Record; - row_view_mode: string; - row_edit_mode: string; -} - -export interface TableRole { - id: string; - table_id: string | null; - name: string; - role_type: string; - capabilities: Record; - is_system: boolean; - sys_create_datetime?: string; -} - -export interface Collaborator { - id: string; - table_id: string; - subject_type: string; - subject_id: string; - role_id: string; - role_name?: string; - role_type?: string; - subject_name?: string; - subject_avatar?: string; - sys_create_datetime?: string; -} - -export interface FieldPermItem { - field_id: string; - access: string; -} - -export interface FieldPermMatrix { - role_id: string; - role_name: string; - role_type: string; - fields: FieldPermItem[]; -} - -export interface RowRule { - id: string; - table_id: string; - role_id: string; - rule_type: string; - mode: string; - conditions: Record[]; -} - -export function getMyPermissionApi(tableId: string) { - return requestClient.get(`${BASE}/tables/${tableId}/my-permission`); -} - -export function getRolesApi(tableId: string) { - return requestClient.get(`${BASE}/tables/${tableId}/roles`); -} - -export function createRoleApi(tableId: string, data: { name: string; capabilities: Record }) { - return requestClient.post(`${BASE}/tables/${tableId}/roles`, data); -} - -export function updateRoleApi(tableId: string, roleId: string, data: { name?: string; capabilities?: Record }) { - return requestClient.put(`${BASE}/tables/${tableId}/roles/${roleId}`, data); -} - -export function deleteRoleApi(tableId: string, roleId: string) { - return requestClient.delete(`${BASE}/tables/${tableId}/roles/${roleId}`); -} - -export function getCollaboratorsApi(tableId: string) { - return requestClient.get(`${BASE}/tables/${tableId}/collaborators`); -} - -export function addCollaboratorApi(tableId: string, data: { subject_type: string; subject_id: string; role_id: string }) { - return requestClient.post(`${BASE}/tables/${tableId}/collaborators`, data); -} - -export function updateCollaboratorApi(tableId: string, collabId: string, data: { role_id: string }) { - return requestClient.put(`${BASE}/tables/${tableId}/collaborators/${collabId}`, data); -} - -export function removeCollaboratorApi(tableId: string, collabId: string) { - return requestClient.delete(`${BASE}/tables/${tableId}/collaborators/${collabId}`); -} - -export function getFieldPermissionsApi(tableId: string) { - return requestClient.get(`${BASE}/tables/${tableId}/field-permissions`); -} - -export function updateFieldPermissionsApi(tableId: string, data: { role_id: string; permissions: FieldPermItem[] }) { - return requestClient.put(`${BASE}/tables/${tableId}/field-permissions`, data); -} - -export function getRowRulesApi(tableId: string) { - return requestClient.get(`${BASE}/tables/${tableId}/row-rules`); -} - -export function updateRowRuleApi(tableId: string, data: { role_id: string; rule_type: string; mode: string; conditions: Record[] }) { - return requestClient.put(`${BASE}/tables/${tableId}/row-rules`, data); -} - -// ==================== Document Version API ==================== - -export interface DocumentVersionItem { - id: string; - document_id: string; - version: number; - title?: string; - change_summary?: string; - content_size: number; - sys_create_datetime?: string; - sys_creator_id?: string; - creator_name?: string; - creator_avatar?: string; -} - -export interface DocumentVersionDetail extends DocumentVersionItem { - content: Record; -} - -export interface DocumentVersionCompare { - version_from: DocumentVersionDetail; - version_to: DocumentVersionDetail; -} - -export function getDocumentVersionsApi(tableId: string, page = 1, pageSize = 20) { - return requestClient.get<{ items: DocumentVersionItem[]; total: number }>( - `${BASE}/tables/${tableId}/versions`, - { params: { page, pageSize } }, - ); -} - -export function getDocumentVersionDetailApi(versionId: string) { - return requestClient.get(`${BASE}/versions/${versionId}`); -} - -export function createDocumentVersionApi(tableId: string, changeSummary?: string) { - return requestClient.post( - `${BASE}/tables/${tableId}/versions`, - { change_summary: changeSummary }, - ); -} - -export function restoreDocumentVersionApi(tableId: string, versionId: string) { - return requestClient.post(`${BASE}/tables/${tableId}/versions/${versionId}/restore`); -} - -export function compareDocumentVersionsApi(tableId: string, fromId: string, toId: string) { - return requestClient.get( - `${BASE}/tables/${tableId}/versions/compare`, - { params: { from: fromId, to: toId } }, - ); -} - -export function deleteDocumentVersionApi(versionId: string) { - return requestClient.delete(`${BASE}/versions/${versionId}`); -} - -// ==================== Document Template API ==================== - -export interface DocumentTemplateItem { - id: string; - name: string; - description?: string; - icon: string; - category: string; - preview_image?: string; - is_system: boolean; - use_count: number; - sys_create_datetime?: string; - sys_update_datetime?: string; - sys_creator_id?: string; - creator_name?: string; -} - -export interface DocumentTemplateDetail extends DocumentTemplateItem { - content: Record; -} - -export function getDocumentTemplatesApi(params?: { category?: string; keyword?: string; page?: number; pageSize?: number }) { - return requestClient.get<{ items: DocumentTemplateItem[]; total: number }>( - `${BASE}/document-templates`, - { params }, - ); -} - -export function getDocumentTemplateCategoriesApi() { - return requestClient.get(`${BASE}/document-templates/categories`); -} - -export function getDocumentTemplateDetailApi(templateId: string) { - return requestClient.get(`${BASE}/document-templates/${templateId}`); -} - -export function createDocumentTemplateApi(data: { - name: string; - description?: string; - icon?: string; - category?: string; - content: Record; - preview_image?: string; -}) { - return requestClient.post(`${BASE}/document-templates`, data); -} - -export function createTemplateFromDocumentApi(documentId: string, data: { - name: string; - description?: string; - category?: string; - content: Record; -}) { - return requestClient.post( - `${BASE}/document-templates/from-document/${documentId}`, - data, - ); -} - -export function updateDocumentTemplateApi(templateId: string, data: { - name?: string; - description?: string; - icon?: string; - category?: string; - content?: Record; - preview_image?: string; -}) { - return requestClient.put(`${BASE}/document-templates/${templateId}`, data); -} - -export function deleteDocumentTemplateApi(templateId: string) { - return requestClient.delete(`${BASE}/document-templates/${templateId}`); -} - -export function useDocumentTemplateApi(templateId: string) { - return requestClient.post(`${BASE}/document-templates/${templateId}/use`); -} - -// ==================== Wiki Space API ==================== - -export interface WikiSpaceItem { - id: string; - name: string; - icon: string; - avatar?: string | null; - description?: string; - cover?: string; - category: string; - visibility: string; - sort: number; - document_count?: number; - sys_create_datetime?: string; - sys_update_datetime?: string; - sys_creator_id?: string; - creator_name?: string; -} - -export interface WikiSpaceDetail extends WikiSpaceItem { - documents: SmartTableItem[]; -} - -export function getWikiSpacesApi() { - return requestClient.get(`${BASE}/wiki-spaces`); -} - -export function getWikiSpaceDetailApi(spaceId: string) { - return requestClient.get(`${BASE}/wiki-spaces/${spaceId}`); -} - -export function createWikiSpaceApi(data: { - name: string; - icon?: string; - avatar?: string | null; - description?: string; - cover?: string; - category?: string; - visibility?: string; -}) { - return requestClient.post(`${BASE}/wiki-spaces`, data); -} - -export function updateWikiSpaceApi(spaceId: string, data: Partial) { - return requestClient.put(`${BASE}/wiki-spaces/${spaceId}`, data); -} - -export function deleteWikiSpaceApi(spaceId: string) { - return requestClient.delete(`${BASE}/wiki-spaces/${spaceId}`); -} - -export function getWikiSpaceDocumentsApi(spaceId: string) { - return requestClient.get(`${BASE}/wiki-spaces/${spaceId}/documents`); -} - -export function createWikiDocumentApi(spaceId: string, data: { - name: string; - parent_id?: string | null; - content?: any; -}) { - return requestClient.post( - `${BASE}/wiki-spaces/${spaceId}/documents`, - { ...data, type: 'document', icon: 'FileText' }, - ); -} diff --git a/web/apps/web-ele/src/components/contract-design/components/AttributePanel.vue b/web/apps/web-ele/src/components/contract-design/components/AttributePanel.vue deleted file mode 100644 index 6cb91cf..0000000 --- a/web/apps/web-ele/src/components/contract-design/components/AttributePanel.vue +++ /dev/null @@ -1,981 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/contract-design/components/ContractRenderer.vue b/web/apps/web-ele/src/components/contract-design/components/ContractRenderer.vue deleted file mode 100644 index 6c65b6f..0000000 --- a/web/apps/web-ele/src/components/contract-design/components/ContractRenderer.vue +++ /dev/null @@ -1,569 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/contract-design/components/ContractSignDialog.vue b/web/apps/web-ele/src/components/contract-design/components/ContractSignDialog.vue deleted file mode 100644 index 3590364..0000000 --- a/web/apps/web-ele/src/components/contract-design/components/ContractSignDialog.vue +++ /dev/null @@ -1,356 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/contract-design/components/DesignCanvas.vue b/web/apps/web-ele/src/components/contract-design/components/DesignCanvas.vue deleted file mode 100644 index f2a4b85..0000000 --- a/web/apps/web-ele/src/components/contract-design/components/DesignCanvas.vue +++ /dev/null @@ -1,376 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/contract-design/components/ElementRenderer.vue b/web/apps/web-ele/src/components/contract-design/components/ElementRenderer.vue deleted file mode 100644 index de759d0..0000000 --- a/web/apps/web-ele/src/components/contract-design/components/ElementRenderer.vue +++ /dev/null @@ -1,714 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/contract-design/components/ElementWrapper.vue b/web/apps/web-ele/src/components/contract-design/components/ElementWrapper.vue deleted file mode 100644 index 92a672c..0000000 --- a/web/apps/web-ele/src/components/contract-design/components/ElementWrapper.vue +++ /dev/null @@ -1,538 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/contract-design/components/MaterialPanel.vue b/web/apps/web-ele/src/components/contract-design/components/MaterialPanel.vue deleted file mode 100644 index 95b4c48..0000000 --- a/web/apps/web-ele/src/components/contract-design/components/MaterialPanel.vue +++ /dev/null @@ -1,971 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/contract-design/components/PreviewModal.vue b/web/apps/web-ele/src/components/contract-design/components/PreviewModal.vue deleted file mode 100644 index e53099a..0000000 --- a/web/apps/web-ele/src/components/contract-design/components/PreviewModal.vue +++ /dev/null @@ -1,284 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/contract-design/components/SignatureDialog.vue b/web/apps/web-ele/src/components/contract-design/components/SignatureDialog.vue deleted file mode 100644 index a08e88a..0000000 --- a/web/apps/web-ele/src/components/contract-design/components/SignatureDialog.vue +++ /dev/null @@ -1,254 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/contract-design/components/SignaturePad.vue b/web/apps/web-ele/src/components/contract-design/components/SignaturePad.vue deleted file mode 100644 index c653892..0000000 --- a/web/apps/web-ele/src/components/contract-design/components/SignaturePad.vue +++ /dev/null @@ -1,283 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/contract-design/components/VariableForm.vue b/web/apps/web-ele/src/components/contract-design/components/VariableForm.vue deleted file mode 100644 index 069287f..0000000 --- a/web/apps/web-ele/src/components/contract-design/components/VariableForm.vue +++ /dev/null @@ -1,343 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/contract-design/index.ts b/web/apps/web-ele/src/components/contract-design/index.ts deleted file mode 100644 index 6a56045..0000000 --- a/web/apps/web-ele/src/components/contract-design/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -export { default as ContractRenderer } from './components/ContractRenderer.vue'; -export { default as ContractSignDialog } from './components/ContractSignDialog.vue'; -export { default as ElementRenderer } from './components/ElementRenderer.vue'; -export { default as SignatureDialog } from './components/SignatureDialog.vue'; -export { default as SignaturePad } from './components/SignaturePad.vue'; -export { default as VariableForm } from './components/VariableForm.vue'; -export { default as ContractDesign } from './index.vue'; -export { useContractDesignStore } from './store/contractDesignStore'; -export type { - ContractElement, - ContractElementType, - ContractMaterial, - ContractTemplateConfig, - PartyType, - SignatureConfig, - TableColumnConfig, - VariableConfig, - VariableType, -} from './store/contractDesignStore'; -export { useContractSignStore } from './store/contractSignStore'; -export type { SignatureData, VariableData } from './store/contractSignStore'; diff --git a/web/apps/web-ele/src/components/contract-design/index.vue b/web/apps/web-ele/src/components/contract-design/index.vue deleted file mode 100644 index 4324022..0000000 --- a/web/apps/web-ele/src/components/contract-design/index.vue +++ /dev/null @@ -1,323 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/contract-design/store/contractDesignStore.ts b/web/apps/web-ele/src/components/contract-design/store/contractDesignStore.ts deleted file mode 100644 index 1ddaf89..0000000 --- a/web/apps/web-ele/src/components/contract-design/store/contractDesignStore.ts +++ /dev/null @@ -1,659 +0,0 @@ -import { computed, nextTick, ref } from 'vue'; - -import { defineStore } from 'pinia'; -import { v4 as uuidv4 } from 'uuid'; - -// 合同元素类型 -export type ContractElementType = - | 'date-zone' // 日期区 - | 'divider' // 分割线 - | 'image' // 图片 - | 'page-break' // 分页符 - | 'paragraph' // 段落 - | 'rich-text' // 富文本 - | 'seal-zone' // 盖章区 - | 'signature-zone' // 签名区 - | 'table' // 表格 - | 'title' // 标题 - | 'variable'; // 变量占位符 - -// 变量类型 -export type VariableType = - | 'date' // 日期 - | 'money' // 金额 - | 'number' // 数字 - | 'select' // 选择 - | 'text'; // 文本 - -// 签署方类型 -export type PartyType = 'party_a' | 'party_b' | 'party_c' | 'witness'; - -// 变量配置 -export interface VariableConfig { - code: string; // 变量编码 - name: string; // 变量名称 - type: VariableType; // 变量类型 - required: boolean; // 是否必填 - defaultValue?: string; // 默认值 - options?: { label: string; value: string }[]; // 选项(select类型) - format?: string; // 格式(日期/金额) -} - -// 签名区配置 -export interface SignatureConfig { - partyType: PartyType; // 签署方 - partyLabel: string; // 签署方标签 - showDate: boolean; // 显示签署日期 - showSeal: boolean; // 显示印章位置 - required: boolean; // 是否必签 -} - -// 表格列配置 -export interface TableColumnConfig { - key: string; - title: string; - width?: number; - align?: 'center' | 'left' | 'right'; -} - -// 合同元素 -export interface ContractElement { - id: string; - type: ContractElementType; - props: Record; - // 变量配置 - variable?: VariableConfig; - // 签名配置 - signature?: SignatureConfig; - // 表格配置 - tableColumns?: TableColumnConfig[]; - tableData?: Record[]; -} - -// 合同模板配置 -export interface ContractTemplateConfig { - id: string; - name: string; - code: string; - category: string; - description: string; - // 页面设置 - pageSize: 'A4' | 'A5' | 'Letter'; - pageMargin: { bottom: number; left: number; right: number; top: number }; - // 元素列表 - elements: ContractElement[]; - // 变量定义 - variables: VariableConfig[]; - // 签署方定义 - parties: { label: string; required: boolean; type: PartyType }[]; -} - -// 预定义变量 -export const predefinedVariables: VariableConfig[] = [ - { code: 'party_a_name', name: '甲方名称', type: 'text', required: true }, - { - code: 'party_a_legal_person', - name: '甲方法定代表人', - type: 'text', - required: false, - }, - { code: 'party_a_address', name: '甲方地址', type: 'text', required: false }, - { code: 'party_a_phone', name: '甲方电话', type: 'text', required: false }, - { code: 'party_b_name', name: '乙方名称', type: 'text', required: true }, - { - code: 'party_b_legal_person', - name: '乙方法定代表人', - type: 'text', - required: false, - }, - { code: 'party_b_address', name: '乙方地址', type: 'text', required: false }, - { code: 'party_b_phone', name: '乙方电话', type: 'text', required: false }, - { code: 'contract_no', name: '合同编号', type: 'text', required: true }, - { - code: 'contract_amount', - name: '合同金额', - type: 'money', - required: false, - format: '¥#,##0.00', - }, - { - code: 'sign_date', - name: '签订日期', - type: 'date', - required: true, - format: 'YYYY年MM月DD日', - }, - { - code: 'start_date', - name: '开始日期', - type: 'date', - required: false, - format: 'YYYY年MM月DD日', - }, - { - code: 'end_date', - name: '结束日期', - type: 'date', - required: false, - format: 'YYYY年MM月DD日', - }, - { code: 'sign_location', name: '签订地点', type: 'text', required: false }, -]; - -// 合同元素材料定义 -export interface ContractMaterial { - type: ContractElementType; - title: string; - icon: string; - category: 'layout' | 'signature' | 'text' | 'variable'; - defaultProps: Record; -} - -// 预定义合同元素材料 -export const contractMaterials: ContractMaterial[] = [ - // 文本元素 - { - type: 'title', - title: '合同标题', - icon: 'Heading1', - category: 'text', - defaultProps: { - content: '合同标题', - level: 1, - align: 'center', - fontSize: 24, - fontWeight: 'bold', - }, - }, - { - type: 'paragraph', - title: '段落文本', - icon: 'AlignLeft', - category: 'text', - defaultProps: { - content: '请输入段落内容...', - align: 'left', - fontSize: 14, - lineHeight: 1.8, - indent: 2, // 首行缩进(字符数) - }, - }, - { - type: 'rich-text', - title: '富文本', - icon: 'FileText', - category: 'text', - defaultProps: { - content: '

请输入富文本内容...

', - minHeight: 100, - padding: 8, - showBorder: false, - borderColor: 'var(--el-border-color)', - backgroundColor: '', - }, - }, - // 变量元素 - { - type: 'variable', - title: '变量占位符', - icon: 'Code', - category: 'variable', - defaultProps: { - variableCode: '', - placeholder: '______', - underline: true, - minWidth: 100, - }, - }, - // 表格元素 - { - type: 'table', - title: '表格', - icon: 'Table', - category: 'text', - defaultProps: { - bordered: true, - headerBgColor: 'var(--el-fill-color-light)', - }, - }, - // 签署元素 - { - type: 'signature-zone', - title: '签名区', - icon: 'Pencil', - category: 'signature', - defaultProps: { - width: 200, - height: 80, - label: '签名', - showBorder: true, - showLabel: true, // 签字后是否显示标签 - align: 'right', // 默认靠右对齐 - }, - }, - { - type: 'seal-zone', - title: '盖章区', - icon: 'Circle', - category: 'signature', - defaultProps: { - width: 120, - height: 120, - label: '盖章处', - showBorder: true, - showLabel: true, // 盖章后是否显示标签 - align: 'right', // 默认靠右对齐 - }, - }, - { - type: 'date-zone', - title: '日期区', - icon: 'Calendar', - category: 'signature', - defaultProps: { - format: 'YYYY年MM月DD日', - label: '日期', - showUnderline: true, - align: 'right', // 默认靠右对齐 - }, - }, - // 布局元素 - { - type: 'divider', - title: '分割线', - icon: 'Minus', - category: 'layout', - defaultProps: { - style: 'solid', - color: 'var(--el-border-color)', - margin: 16, - }, - }, - { - type: 'page-break', - title: '分页符', - icon: 'FileText', - category: 'layout', - defaultProps: {}, - }, - { - type: 'image', - title: '图片', - icon: 'Image', - category: 'layout', - defaultProps: { - src: '', - width: 200, - height: 'auto', - align: 'center', - }, - }, -]; - -export const useContractDesignStore = defineStore('contract-design', () => { - // 当前选中的元素 - const activeId = ref(null); - - // 合同模板配置 - const templateConfig = ref({ - id: uuidv4(), - name: '新建合同模板', - code: '', - category: '', - description: '', - pageSize: 'A4', - pageMargin: { top: 60, right: 60, bottom: 60, left: 60 }, - elements: [], - variables: [...predefinedVariables], - parties: [ - { type: 'party_a', label: '甲方', required: true }, - { type: 'party_b', label: '乙方', required: true }, - ], - }); - - // 历史记录 - const history = ref([]); - const historyIndex = ref(-1); - const isTimeTravel = ref(false); - - // 剪贴板 - const clipboard = ref(null); - - // 拖拽状态 - const isDragging = ref(false); - - // 预览模式 - const isPreview = ref(false); - - // 记录快照 - const recordSnapshot = () => { - if (isTimeTravel.value) return; - - if (historyIndex.value < history.value.length - 1) { - history.value.splice(historyIndex.value + 1); - } - - history.value.push(JSON.stringify(templateConfig.value)); - historyIndex.value = history.value.length - 1; - - if (history.value.length > 30) { - history.value.shift(); - historyIndex.value--; - } - }; - - const canUndo = computed(() => historyIndex.value > 0); - const canRedo = computed(() => historyIndex.value < history.value.length - 1); - - const undo = () => { - if (!canUndo.value) return; - - isTimeTravel.value = true; - historyIndex.value--; - const snapshot = history.value[historyIndex.value]; - if (snapshot) { - templateConfig.value = JSON.parse(snapshot); - } - - nextTick(() => { - isTimeTravel.value = false; - }); - }; - - const redo = () => { - if (!canRedo.value) return; - - isTimeTravel.value = true; - historyIndex.value++; - const snapshot = history.value[historyIndex.value]; - if (snapshot) { - templateConfig.value = JSON.parse(snapshot); - } - - nextTick(() => { - isTimeTravel.value = false; - }); - }; - - // 设置当前选中 - const setActive = (id: null | string) => { - activeId.value = id; - }; - - // 获取当前选中的元素 - const activeElement = computed(() => { - if (!activeId.value) return null; - return ( - templateConfig.value.elements.find((e) => e.id === activeId.value) || null - ); - }); - - // 添加元素 - const addElement = (material: ContractMaterial, index?: number) => { - const id = uuidv4(); - const element: ContractElement = { - id, - type: material.type, - props: JSON.parse(JSON.stringify(material.defaultProps)), - }; - - // 如果是表格,初始化列和数据 - if (material.type === 'table') { - element.tableColumns = [ - { key: 'col1', title: '列1', width: 100, align: 'center' }, - { key: 'col2', title: '列2', width: 100, align: 'center' }, - { key: 'col3', title: '列3', width: 100, align: 'center' }, - ]; - element.tableData = [{ col1: '', col2: '', col3: '' }]; - } - - // 如果是签名区,初始化签名配置 - if (material.type === 'signature-zone' || material.type === 'seal-zone') { - element.signature = { - partyType: 'party_a', - partyLabel: '甲方', - showDate: true, - showSeal: material.type === 'seal-zone', - required: true, - }; - } - - if (typeof index === 'number') { - templateConfig.value.elements.splice(index, 0, element); - } else { - templateConfig.value.elements.push(element); - } - - activeId.value = id; - recordSnapshot(); - }; - - // 删除元素 - const deleteElement = (id: string) => { - const index = templateConfig.value.elements.findIndex((e) => e.id === id); - if (index !== -1) { - templateConfig.value.elements.splice(index, 1); - if (activeId.value === id) { - activeId.value = null; - } - recordSnapshot(); - } - }; - - // 复制元素 - const copyElement = (id: string) => { - const element = templateConfig.value.elements.find((e) => e.id === id); - if (!element) return; - - const newId = uuidv4(); - const newElement: ContractElement = { - ...JSON.parse(JSON.stringify(element)), - id: newId, - }; - - const index = templateConfig.value.elements.findIndex((e) => e.id === id); - templateConfig.value.elements.splice(index + 1, 0, newElement); - activeId.value = newId; - recordSnapshot(); - }; - - // 复制到剪贴板 - const copyToClipboard = (id: string) => { - const element = templateConfig.value.elements.find((e) => e.id === id); - if (element) { - clipboard.value = JSON.parse(JSON.stringify(element)); - } - }; - - // 从剪贴板粘贴 - const pasteFromClipboard = () => { - if (!clipboard.value) return false; - - const newId = uuidv4(); - const newElement: ContractElement = { - ...JSON.parse(JSON.stringify(clipboard.value)), - id: newId, - }; - - templateConfig.value.elements.push(newElement); - activeId.value = newId; - recordSnapshot(); - return true; - }; - - // 检查剪贴板是否有内容 - const hasClipboard = computed(() => clipboard.value !== null); - - // 更新元素属性 - const updateElementProps = (id: string, props: Record) => { - const element = templateConfig.value.elements.find((e) => e.id === id); - if (element) { - element.props = { ...element.props, ...props }; - - // 如果是变量占位符,且选择了变量,自动添加到模板变量列表 - if (element.type === 'variable' && props.variableCode) { - const varConfig = predefinedVariables.find( - (v) => v.code === props.variableCode, - ); - if (varConfig) { - const exists = templateConfig.value.variables.find( - (v) => v.code === varConfig.code, - ); - if (!exists) { - templateConfig.value.variables.push({ ...varConfig }); - } - } - } - } - }; - - // 更新元素 - const updateElement = (id: string, updates: Partial) => { - const element = templateConfig.value.elements.find((e) => e.id === id); - if (element) { - Object.assign(element, updates); - recordSnapshot(); - } - }; - - // 移动元素 - const moveElement = (id: string, direction: 'down' | 'up') => { - const elements = templateConfig.value.elements; - const index = elements.findIndex((e) => e.id === id); - if (index === -1) return; - - const newIndex = direction === 'up' ? index - 1 : index + 1; - if (newIndex < 0 || newIndex >= elements.length) return; - - [elements[index], elements[newIndex]] = [ - elements[newIndex]!, - elements[index]!, - ]; - recordSnapshot(); - }; - - // 设置拖拽状态 - const setDragging = (val: boolean) => { - isDragging.value = val; - }; - - // 设置预览模式 - const setPreview = (val: boolean) => { - isPreview.value = val; - }; - - // 清空画布 - const clearCanvas = () => { - templateConfig.value.elements = []; - activeId.value = null; - recordSnapshot(); - }; - - // 添加变量 - const addVariable = (variable: VariableConfig) => { - const exists = templateConfig.value.variables.find( - (v) => v.code === variable.code, - ); - if (!exists) { - templateConfig.value.variables.push(variable); - recordSnapshot(); - } - }; - - // 删除变量 - const removeVariable = (code: string) => { - const index = templateConfig.value.variables.findIndex( - (v) => v.code === code, - ); - if (index !== -1) { - templateConfig.value.variables.splice(index, 1); - recordSnapshot(); - } - }; - - // 更新模板基础配置 - const updateTemplateConfig = (config: Partial) => { - Object.assign(templateConfig.value, config); - }; - - // 导出配置 - const exportConfig = () => { - return JSON.stringify(templateConfig.value, null, 2); - }; - - // 导入配置 - const importConfig = (json: string) => { - try { - const config = JSON.parse(json); - templateConfig.value = config; - activeId.value = null; - recordSnapshot(); - return true; - } catch { - return false; - } - }; - - // 克隆元素(用于拖拽) - const cloneElement = (material: ContractMaterial): ContractElement => { - const id = uuidv4(); - const element: ContractElement = { - id, - type: material.type, - props: JSON.parse(JSON.stringify(material.defaultProps)), - }; - - if (material.type === 'table') { - element.tableColumns = [ - { key: 'col1', title: '列1', width: 100, align: 'center' }, - { key: 'col2', title: '列2', width: 100, align: 'center' }, - { key: 'col3', title: '列3', width: 100, align: 'center' }, - ]; - element.tableData = [{ col1: '', col2: '', col3: '' }]; - } - - if (material.type === 'signature-zone' || material.type === 'seal-zone') { - element.signature = { - partyType: 'party_a', - partyLabel: '甲方', - showDate: true, - showSeal: material.type === 'seal-zone', - required: true, - }; - } - - return element; - }; - - return { - activeId, - activeElement, - templateConfig, - isDragging, - isPreview, - canUndo, - canRedo, - hasClipboard, - setActive, - addElement, - deleteElement, - copyElement, - copyToClipboard, - pasteFromClipboard, - updateElementProps, - updateElement, - moveElement, - setDragging, - setPreview, - clearCanvas, - addVariable, - removeVariable, - updateTemplateConfig, - exportConfig, - importConfig, - cloneElement, - undo, - redo, - recordSnapshot, - }; -}); diff --git a/web/apps/web-ele/src/components/contract-design/store/contractSignStore.ts b/web/apps/web-ele/src/components/contract-design/store/contractSignStore.ts deleted file mode 100644 index 7da98a3..0000000 --- a/web/apps/web-ele/src/components/contract-design/store/contractSignStore.ts +++ /dev/null @@ -1,181 +0,0 @@ -import type { ContractTemplateConfig, PartyType } from './contractDesignStore'; - -import { computed, ref } from 'vue'; - -import { defineStore } from 'pinia'; - -// 签署数据 -export interface SignatureData { - elementId: string; // 对应的元素 ID - partyType: PartyType; // 签署方类型 - partyLabel: string; // 签署方标签 - signatureImage: string; // 签名图片(base64) - signedAt: string; // 签署时间 - signedBy?: string; // 签署人 -} - -// 变量填写数据 -export interface VariableData { - code: string; - value: string; -} - -// 合同签署状态 -export interface ContractSignState { - contractId: string; - templateConfig: ContractTemplateConfig | null; - signatures: SignatureData[]; - variables: VariableData[]; - status: 'completed' | 'draft' | 'signing'; - startedAt?: string; - completedAt?: string; -} - -export const useContractSignStore = defineStore('contract-sign', () => { - // 合同模板配置 - const templateConfig = ref(null); - - // 签署数据 - const signatures = ref([]); - - // 变量数据 - const variables = ref([]); - - // 签署状态 - const status = ref<'completed' | 'draft' | 'signing'>('draft'); - - // 加载合同模板 - const loadTemplate = (config: ContractTemplateConfig) => { - templateConfig.value = JSON.parse(JSON.stringify(config)); - signatures.value = []; - variables.value = []; - status.value = 'signing'; - }; - - // 获取元素的签名数据 - const getSignature = (elementId: string): SignatureData | undefined => { - return signatures.value.find((s) => s.elementId === elementId); - }; - - // 添加或更新签名 - const setSignature = (data: Omit) => { - const index = signatures.value.findIndex( - (s) => s.elementId === data.elementId, - ); - const signatureData: SignatureData = { - ...data, - signedAt: new Date().toISOString(), - }; - - if (index === -1) { - signatures.value.push(signatureData); - } else { - signatures.value[index] = signatureData; - } - }; - - // 移除签名 - const removeSignature = (elementId: string) => { - const index = signatures.value.findIndex((s) => s.elementId === elementId); - if (index !== -1) { - signatures.value.splice(index, 1); - } - }; - - // 获取变量值 - const getVariable = (code: string): string => { - const variable = variables.value.find((v) => v.code === code); - return variable?.value || ''; - }; - - // 设置变量值 - const setVariable = (code: string, value: string) => { - const index = variables.value.findIndex((v) => v.code === code); - if (index === -1) { - variables.value.push({ code, value }); - } else { - variables.value[index]!.value = value; - } - }; - - // 获取所有需要签署的元素 - const signatureElements = computed(() => { - if (!templateConfig.value) return []; - return templateConfig.value.elements.filter( - (e) => e.type === 'signature-zone' || e.type === 'seal-zone', - ); - }); - - // 获取所有必须签署的元素 - const requiredSignatureElements = computed(() => { - return signatureElements.value.filter((e) => e.signature?.required); - }); - - // 检查是否所有必须签署的元素都已签署 - const allRequiredSigned = computed(() => { - return requiredSignatureElements.value.every((e) => - signatures.value.some((s) => s.elementId === e.id), - ); - }); - - // 获取签署进度 - const signProgress = computed(() => { - const total = requiredSignatureElements.value.length; - if (total === 0) return 100; - - const signed = requiredSignatureElements.value.filter((e) => - signatures.value.some((s) => s.elementId === e.id), - ).length; - - return Math.round((signed / total) * 100); - }); - - // 完成签署 - const completeSign = () => { - if (!allRequiredSigned.value) { - return false; - } - status.value = 'completed'; - return true; - }; - - // 重置 - const reset = () => { - templateConfig.value = null; - signatures.value = []; - variables.value = []; - status.value = 'draft'; - }; - - // 导出签署后的合同数据 - const exportSignedContract = () => { - return { - template: templateConfig.value, - signatures: signatures.value, - variables: variables.value, - status: status.value, - completedAt: - status.value === 'completed' ? new Date().toISOString() : undefined, - }; - }; - - return { - templateConfig, - signatures, - variables, - status, - signatureElements, - requiredSignatureElements, - allRequiredSigned, - signProgress, - loadTemplate, - getSignature, - setSignature, - removeSignature, - getVariable, - setVariable, - completeSign, - reset, - exportSignedContract, - }; -}); diff --git a/web/apps/web-ele/src/components/contract-design/templates/sampleContract.ts b/web/apps/web-ele/src/components/contract-design/templates/sampleContract.ts deleted file mode 100644 index 5e3f46b..0000000 --- a/web/apps/web-ele/src/components/contract-design/templates/sampleContract.ts +++ /dev/null @@ -1,350 +0,0 @@ -import type { ContractTemplateConfig } from '../store/contractDesignStore'; - -// 示例合同模板 - 简单采购合同 -export const samplePurchaseContract: ContractTemplateConfig = { - id: 'sample-purchase-001', - name: '采购合同模板', - code: 'PURCHASE_CONTRACT', - category: '采购类', - description: '标准采购合同模板,适用于一般商品采购场景', - pageSize: 'A4', - pageMargin: { top: 60, right: 60, bottom: 60, left: 60 }, - elements: [ - { - id: 'title-1', - type: 'title', - props: { - content: '采购合同', - level: 1, - align: 'center', - fontSize: 24, - fontWeight: 'bold', - }, - }, - { - id: 'contract-no', - type: 'paragraph', - props: { - content: '合同编号:{{contract_no}}', - align: 'right', - fontSize: 14, - lineHeight: 1.8, - indent: 0, - }, - }, - { - id: 'divider-1', - type: 'divider', - props: { - style: 'solid', - color: 'var(--el-border-color)', - margin: 16, - }, - }, - { - id: 'party-info', - type: 'paragraph', - props: { - content: - '甲方(采购方):{{party_a_name}}\n地址:{{party_a_address}}\n联系电话:{{party_a_phone}}\n\n乙方(供应方):{{party_b_name}}\n地址:{{party_b_address}}\n联系电话:{{party_b_phone}}', - align: 'left', - fontSize: 14, - lineHeight: 1.8, - indent: 0, - }, - }, - { - id: 'divider-2', - type: 'divider', - props: { - style: 'dashed', - color: 'var(--el-border-color)', - margin: 16, - }, - }, - { - id: 'intro', - type: 'paragraph', - props: { - content: - '甲乙双方经友好协商,就甲方向乙方采购相关产品事宜,达成如下协议:', - align: 'left', - fontSize: 14, - lineHeight: 1.8, - indent: 2, - }, - }, - { - id: 'article-1', - type: 'title', - props: { - content: '第一条 采购内容', - level: 3, - align: 'left', - fontSize: 16, - fontWeight: 'bold', - }, - }, - { - id: 'article-1-content', - type: 'paragraph', - props: { - content: - '甲方向乙方采购以下产品(详见附件清单),合同总金额为人民币 {{contract_amount}} 元整。', - align: 'left', - fontSize: 14, - lineHeight: 1.8, - indent: 2, - }, - }, - { - id: 'article-2', - type: 'title', - props: { - content: '第二条 交付方式', - level: 3, - align: 'left', - fontSize: 16, - fontWeight: 'bold', - }, - }, - { - id: 'article-2-content', - type: 'paragraph', - props: { - content: - '乙方应于合同签订后30个工作日内完成产品交付。交付地点为甲方指定地址。', - align: 'left', - fontSize: 14, - lineHeight: 1.8, - indent: 2, - }, - }, - { - id: 'article-3', - type: 'title', - props: { - content: '第三条 付款方式', - level: 3, - align: 'left', - fontSize: 16, - fontWeight: 'bold', - }, - }, - { - id: 'article-3-content', - type: 'paragraph', - props: { - content: '甲方应于产品验收合格后15个工作日内,向乙方支付全部合同款项。', - align: 'left', - fontSize: 14, - lineHeight: 1.8, - indent: 2, - }, - }, - { - id: 'article-4', - type: 'title', - props: { - content: '第四条 违约责任', - level: 3, - align: 'left', - fontSize: 16, - fontWeight: 'bold', - }, - }, - { - id: 'article-4-content', - type: 'paragraph', - props: { - content: - '任何一方违反本合同约定,应向对方支付合同总金额10%的违约金,并赔偿由此造成的全部损失。', - align: 'left', - fontSize: 14, - lineHeight: 1.8, - indent: 2, - }, - }, - { - id: 'article-5', - type: 'title', - props: { - content: '第五条 争议解决', - level: 3, - align: 'left', - fontSize: 16, - fontWeight: 'bold', - }, - }, - { - id: 'article-5-content', - type: 'paragraph', - props: { - content: - '本合同在履行过程中发生的争议,由双方协商解决;协商不成的,任何一方均可向合同签订地人民法院提起诉讼。', - align: 'left', - fontSize: 14, - lineHeight: 1.8, - indent: 2, - }, - }, - { - id: 'article-6', - type: 'title', - props: { - content: '第六条 其他', - level: 3, - align: 'left', - fontSize: 16, - fontWeight: 'bold', - }, - }, - { - id: 'article-6-content', - type: 'paragraph', - props: { - content: - '本合同一式两份,甲乙双方各执一份,具有同等法律效力。本合同自双方签字盖章之日起生效。', - align: 'left', - fontSize: 14, - lineHeight: 1.8, - indent: 2, - }, - }, - { - id: 'divider-3', - type: 'divider', - props: { - style: 'solid', - color: 'var(--el-border-color)', - margin: 24, - }, - }, - { - id: 'sign-section-title', - type: 'paragraph', - props: { - content: '(以下为签署区)', - align: 'center', - fontSize: 12, - lineHeight: 1.5, - indent: 0, - }, - }, - { - id: 'sign-party-a', - type: 'paragraph', - props: { - content: '甲方(盖章):', - align: 'left', - fontSize: 14, - lineHeight: 1.8, - indent: 0, - }, - }, - { - id: 'signature-a', - type: 'signature-zone', - props: { - width: 200, - height: 80, - label: '签名', - showBorder: true, - }, - signature: { - partyType: 'party_a', - partyLabel: '甲方签名', - showDate: true, - showSeal: false, - required: true, - }, - }, - { - id: 'date-a', - type: 'date-zone', - props: { - format: 'YYYY年MM月DD日', - label: '签署日期', - showUnderline: true, - }, - }, - { - id: 'sign-party-b', - type: 'paragraph', - props: { - content: '乙方(盖章):', - align: 'left', - fontSize: 14, - lineHeight: 1.8, - indent: 0, - }, - }, - { - id: 'signature-b', - type: 'signature-zone', - props: { - width: 200, - height: 80, - label: '签名', - showBorder: true, - }, - signature: { - partyType: 'party_b', - partyLabel: '乙方签名', - showDate: true, - showSeal: false, - required: true, - }, - }, - { - id: 'date-b', - type: 'date-zone', - props: { - format: 'YYYY年MM月DD日', - label: '签署日期', - showUnderline: true, - }, - }, - ], - variables: [ - { code: 'party_a_name', name: '甲方名称', type: 'text', required: true }, - { - code: 'party_a_address', - name: '甲方地址', - type: 'text', - required: false, - }, - { code: 'party_a_phone', name: '甲方电话', type: 'text', required: false }, - { code: 'party_b_name', name: '乙方名称', type: 'text', required: true }, - { - code: 'party_b_address', - name: '乙方地址', - type: 'text', - required: false, - }, - { code: 'party_b_phone', name: '乙方电话', type: 'text', required: false }, - { code: 'contract_no', name: '合同编号', type: 'text', required: true }, - { - code: 'contract_amount', - name: '合同金额', - type: 'money', - required: true, - format: '¥#,##0.00', - }, - ], - parties: [ - { type: 'party_a', label: '甲方(采购方)', required: true }, - { type: 'party_b', label: '乙方(供应方)', required: true }, - ], -}; - -// 导出所有模板 -export const contractTemplates = [ - { - id: 'sample-purchase', - name: '采购合同', - description: '标准采购合同模板', - icon: 'FileText', - template: samplePurchaseContract, - }, -]; diff --git a/web/apps/web-ele/src/components/contract-design/utils/exportPdf.ts b/web/apps/web-ele/src/components/contract-design/utils/exportPdf.ts deleted file mode 100644 index 1781d18..0000000 --- a/web/apps/web-ele/src/components/contract-design/utils/exportPdf.ts +++ /dev/null @@ -1,283 +0,0 @@ -import html2canvas from 'html2canvas'; -import { jsPDF } from 'jspdf'; - -export interface ExportPdfOptions { - filename?: string; - pageSize?: 'A4' | 'A5' | 'Letter'; - pageMargin?: { bottom: number; left: number; right: number; top: number }; - quality?: number; -} - -// 页面尺寸(单位:mm) -const PAGE_SIZES_MM = { - A4: { width: 210, height: 297 }, - A5: { width: 148, height: 210 }, - Letter: { width: 216, height: 279 }, -}; - -// 页面尺寸(单位:px,96dpi) -const PAGE_SIZES_PX = { - A4: { width: 794, height: 1123 }, - A5: { width: 559, height: 794 }, - Letter: { width: 816, height: 1056 }, -}; - -/** - * 将多个页面元素导出为 PDF - * @param pages 页面元素数组 - * @param options 导出选项 - */ -export async function exportPagesToPdf( - pages: HTMLElement[], - options: ExportPdfOptions = {}, -): Promise { - const { - filename = `contract-${Date.now()}.pdf`, - pageSize = 'A4', - quality = 4, // 提高默认分辨率,3 = 3倍缩放 - } = options; - - const pageConfig = PAGE_SIZES_MM[pageSize]; - - // 创建 PDF - const pdf = new jsPDF({ - orientation: 'portrait', - unit: 'mm', - format: [pageConfig.width, pageConfig.height], - }); - - // 逐页渲染 - for (const [i, page] of pages.entries()) { - // 导出前隐藏不需要的元素(如已签署徽章) - const hiddenElements: HTMLElement[] = []; - page.querySelectorAll('.signed-badge').forEach((el) => { - const htmlEl = el as HTMLElement; - hiddenElements.push(htmlEl); - htmlEl.style.display = 'none'; - }); - - // 导出前移除签名区域的边框和背景样式 - const signedElements: { el: HTMLElement; originalStyle: string }[] = []; - page - .querySelectorAll('.signature-display.signed, .seal-display.signed') - .forEach((el) => { - const htmlEl = el as HTMLElement; - signedElements.push({ - el: htmlEl, - originalStyle: htmlEl.getAttribute('style') || '', - }); - htmlEl.style.border = 'none'; - htmlEl.style.background = 'transparent'; - htmlEl.style.padding = '0'; - }); - - // 使用 html2canvas 将元素转换为 canvas - const canvas = await html2canvas(page, { - scale: quality, - useCORS: true, - allowTaint: true, - backgroundColor: '#ffffff', - logging: false, - }); - - // 导出后恢复隐藏的元素 - hiddenElements.forEach((el) => { - el.style.display = ''; - }); - - // 导出后恢复签名区域的样式 - signedElements.forEach(({ el, originalStyle }) => { - el.setAttribute('style', originalStyle); - }); - - // 计算图片尺寸(填满整页) - const imgData = canvas.toDataURL('image/jpeg', 0.95); - - if (i > 0) { - pdf.addPage(); - } - - // 添加图片,填满整页 - pdf.addImage(imgData, 'JPEG', 0, 0, pageConfig.width, pageConfig.height); - } - - // 下载 PDF - pdf.save(filename); -} - -/** - * 将 HTML 元素导出为 PDF - * @param element 要导出的 HTML 元素 - * @param options 导出选项 - */ -export async function exportToPdf( - element: HTMLElement, - options: ExportPdfOptions = {}, -): Promise { - const { - filename = `contract-${Date.now()}.pdf`, - pageSize = 'A4', - pageMargin = { top: 10, right: 10, bottom: 10, left: 10 }, - quality = 2, - } = options; - - const pageConfig = PAGE_SIZES_MM[pageSize]; - - // 导出前隐藏不需要的元素(如已签署徽章) - const hiddenElements: HTMLElement[] = []; - element.querySelectorAll('.signed-badge').forEach((el) => { - const htmlEl = el as HTMLElement; - hiddenElements.push(htmlEl); - htmlEl.style.display = 'none'; - }); - - // 导出前移除签名区域的边框和背景样式 - const signedElements: { el: HTMLElement; originalStyle: string }[] = []; - element - .querySelectorAll('.signature-display.signed, .seal-display.signed') - .forEach((el) => { - const htmlEl = el as HTMLElement; - signedElements.push({ - el: htmlEl, - originalStyle: htmlEl.getAttribute('style') || '', - }); - htmlEl.style.border = 'none'; - htmlEl.style.background = 'transparent'; - htmlEl.style.padding = '0'; - }); - - // 使用 html2canvas 将元素转换为 canvas - const canvas = await html2canvas(element, { - scale: quality, - useCORS: true, - allowTaint: true, - backgroundColor: '#ffffff', - logging: false, - }); - - // 导出后恢复隐藏的元素 - hiddenElements.forEach((el) => { - el.style.display = ''; - }); - - // 导出后恢复签名区域的样式 - signedElements.forEach(({ el, originalStyle }) => { - el.setAttribute('style', originalStyle); - }); - - // 创建 PDF - const pdf = new jsPDF({ - orientation: 'portrait', - unit: 'mm', - format: [pageConfig.width, pageConfig.height], - }); - - // 计算可用区域(减去边距) - const contentWidth = pageConfig.width - pageMargin.left - pageMargin.right; - const contentHeight = pageConfig.height - pageMargin.top - pageMargin.bottom; - - // 计算图片尺寸(按宽度缩放) - const imgWidth = contentWidth; - const imgHeight = (canvas.height * imgWidth) / canvas.width; - - // 将 canvas 转换为图片数据 - const imgData = canvas.toDataURL('image/jpeg', 0.95); - - // 如果内容高度小于等于一页可用高度,直接添加 - if (imgHeight <= contentHeight) { - pdf.addImage( - imgData, - 'JPEG', - pageMargin.left, - pageMargin.top, - imgWidth, - imgHeight, - ); - } else { - // 需要分页 - let remainingHeight = imgHeight; - let sourceY = 0; - let pageIndex = 0; - - while (remainingHeight > 0) { - if (pageIndex > 0) { - pdf.addPage(); - } - - // 计算当前页显示的内容高度 - const currentPageContentHeight = Math.min(remainingHeight, contentHeight); - - // 计算源图片中对应的像素高度 - const sourceHeight = - (currentPageContentHeight / imgHeight) * canvas.height; - - // 创建临时 canvas 来裁剪当前页的内容 - const tempCanvas = document.createElement('canvas'); - tempCanvas.width = canvas.width; - tempCanvas.height = sourceHeight; - const tempCtx = tempCanvas.getContext('2d'); - - if (tempCtx) { - tempCtx.drawImage( - canvas, - 0, - sourceY, - canvas.width, - sourceHeight, // 源区域 - 0, - 0, - canvas.width, - sourceHeight, // 目标区域 - ); - - const pageImgData = tempCanvas.toDataURL('image/jpeg', 0.95); - pdf.addImage( - pageImgData, - 'JPEG', - pageMargin.left, - pageMargin.top, - imgWidth, - currentPageContentHeight, - ); - } - - sourceY += sourceHeight; - remainingHeight -= contentHeight; - pageIndex++; - } - } - - // 下载 PDF - pdf.save(filename); -} - -/** - * 将合同渲染器导出为 PDF - * @param containerSelector 容器选择器 - * @param options 导出选项 - */ -export async function exportContractToPdf( - containerSelector: string, - options: ExportPdfOptions = {}, -): Promise { - const container = document.querySelector(containerSelector) as HTMLElement; - if (!container) { - console.error('Container not found:', containerSelector); - return false; - } - - // 查找合同纸张元素 - const paper = container.querySelector('.contract-paper') as HTMLElement; - if (!paper) { - console.error('Contract paper not found'); - return false; - } - - try { - await exportToPdf(paper, options); - return true; - } catch (error) { - console.error('Export PDF failed:', error); - return false; - } -} diff --git a/web/apps/web-ele/src/components/import-export-manager/import-export-manager.vue b/web/apps/web-ele/src/components/import-export-manager/import-export-manager.vue deleted file mode 100644 index 7420223..0000000 --- a/web/apps/web-ele/src/components/import-export-manager/import-export-manager.vue +++ /dev/null @@ -1,826 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/import-export-manager/index.ts b/web/apps/web-ele/src/components/import-export-manager/index.ts deleted file mode 100644 index 0696f3b..0000000 --- a/web/apps/web-ele/src/components/import-export-manager/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as ImportExportManager } from './import-export-manager.vue'; -export * from './types'; diff --git a/web/apps/web-ele/src/components/import-export-manager/types.ts b/web/apps/web-ele/src/components/import-export-manager/types.ts deleted file mode 100644 index 885f8e5..0000000 --- a/web/apps/web-ele/src/components/import-export-manager/types.ts +++ /dev/null @@ -1,67 +0,0 @@ -/** 导入结果 */ -export interface ImportResult { - success: number; - failed: number; - errors: ImportError[]; - warnings?: string[]; -} - -/** 导入错误详情 */ -export interface ImportError { - row: number; - field: null | string; - error: string; - type: 'header' | 'option' | 'required' | 'system' | 'type'; -} - -/** 导出选项 */ -export interface ExportOptions { - ids?: string[]; - includeSubTables?: boolean; - filename?: string; -} - -/** 任务状态 */ -export type TaskStatus = - | 'cancelled' - | 'failed' - | 'pending' - | 'running' - | 'success'; - -/** 任务记录 */ -export interface TaskRecord { - id: string; - type: 'export' | 'import'; - filename: string; - status: TaskStatus; - startTime: Date; - endTime?: Date; - progress?: number; - totalCount?: number; // 总条数 - processedCount?: number; // 已处理条数 - result?: ImportResult | { count: number }; - error?: string; - expiresAt?: string; // 任务过期时间 - options?: ExportOptions; // 导出选项,用于重试 -} - -/** 组件 Props */ -export interface ImportExportManagerProps { - /** 表单编码 */ - formCode: string; - /** 表单名称 */ - formName?: string; - /** 是否显示导入功能 */ - showImport?: boolean; - /** 是否显示导出功能 */ - showExport?: boolean; - /** 是否显示下载模板 */ - showTemplate?: boolean; -} - -/** 组件 Emits */ -export interface ImportExportManagerEmits { - (e: 'import-success', result: ImportResult): void; - (e: 'export-success'): void; -} diff --git a/web/apps/web-ele/src/components/wiki/CreateWikiDialog.vue b/web/apps/web-ele/src/components/wiki/CreateWikiDialog.vue deleted file mode 100644 index d253f87..0000000 --- a/web/apps/web-ele/src/components/wiki/CreateWikiDialog.vue +++ /dev/null @@ -1,141 +0,0 @@ - - - diff --git a/web/apps/web-ele/src/components/wiki/EditWikiDialog.vue b/web/apps/web-ele/src/components/wiki/EditWikiDialog.vue deleted file mode 100644 index c21eab2..0000000 --- a/web/apps/web-ele/src/components/wiki/EditWikiDialog.vue +++ /dev/null @@ -1,151 +0,0 @@ - - - diff --git a/web/apps/web-ele/src/components/wiki/WikiHomeSidebar.vue b/web/apps/web-ele/src/components/wiki/WikiHomeSidebar.vue deleted file mode 100644 index efd17de..0000000 --- a/web/apps/web-ele/src/components/wiki/WikiHomeSidebar.vue +++ /dev/null @@ -1,903 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/workflow/DocumentPreviewDialog.vue b/web/apps/web-ele/src/components/workflow/DocumentPreviewDialog.vue deleted file mode 100644 index 481b86b..0000000 --- a/web/apps/web-ele/src/components/workflow/DocumentPreviewDialog.vue +++ /dev/null @@ -1,256 +0,0 @@ - - - diff --git a/web/apps/web-ele/src/components/workflow/detial/FlowPathPreview.vue b/web/apps/web-ele/src/components/workflow/detial/FlowPathPreview.vue deleted file mode 100644 index 741e791..0000000 --- a/web/apps/web-ele/src/components/workflow/detial/FlowPathPreview.vue +++ /dev/null @@ -1,527 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/workflow/detial/FlowProgressTab.vue b/web/apps/web-ele/src/components/workflow/detial/FlowProgressTab.vue deleted file mode 100644 index 25ccbdc..0000000 --- a/web/apps/web-ele/src/components/workflow/detial/FlowProgressTab.vue +++ /dev/null @@ -1,908 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/workflow/detial/InstanceDetailPanel.vue b/web/apps/web-ele/src/components/workflow/detial/InstanceDetailPanel.vue deleted file mode 100644 index c88e9db..0000000 --- a/web/apps/web-ele/src/components/workflow/detial/InstanceDetailPanel.vue +++ /dev/null @@ -1,208 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/workflow/detial/tabs/DocumentTab.vue b/web/apps/web-ele/src/components/workflow/detial/tabs/DocumentTab.vue deleted file mode 100644 index 2976171..0000000 --- a/web/apps/web-ele/src/components/workflow/detial/tabs/DocumentTab.vue +++ /dev/null @@ -1,327 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/workflow/detial/tabs/FlowchartTab.vue b/web/apps/web-ele/src/components/workflow/detial/tabs/FlowchartTab.vue deleted file mode 100644 index 8c7587f..0000000 --- a/web/apps/web-ele/src/components/workflow/detial/tabs/FlowchartTab.vue +++ /dev/null @@ -1,234 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/workflow/detial/tabs/FormTab.vue b/web/apps/web-ele/src/components/workflow/detial/tabs/FormTab.vue deleted file mode 100644 index d14110b..0000000 --- a/web/apps/web-ele/src/components/workflow/detial/tabs/FormTab.vue +++ /dev/null @@ -1,195 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/workflow/detial/tabs/ProgressTab.vue b/web/apps/web-ele/src/components/workflow/detial/tabs/ProgressTab.vue deleted file mode 100644 index fcb1ddd..0000000 --- a/web/apps/web-ele/src/components/workflow/detial/tabs/ProgressTab.vue +++ /dev/null @@ -1,972 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/workflow/index.ts b/web/apps/web-ele/src/components/workflow/index.ts deleted file mode 100644 index 9f8a788..0000000 --- a/web/apps/web-ele/src/components/workflow/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as DocumentPreviewDialog } from './DocumentPreviewDialog.vue'; -export { default as InstanceDetailPanel } from './detial/InstanceDetailPanel.vue'; diff --git a/web/apps/web-ele/src/components/zq-draw/DrawPreview.vue b/web/apps/web-ele/src/components/zq-draw/DrawPreview.vue deleted file mode 100644 index 085987a..0000000 --- a/web/apps/web-ele/src/components/zq-draw/DrawPreview.vue +++ /dev/null @@ -1,140 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/zq-draw/ZqDraw.vue b/web/apps/web-ele/src/components/zq-draw/ZqDraw.vue deleted file mode 100644 index 50a15bf..0000000 --- a/web/apps/web-ele/src/components/zq-draw/ZqDraw.vue +++ /dev/null @@ -1,397 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/zq-draw/components/ContextMenu.vue b/web/apps/web-ele/src/components/zq-draw/components/ContextMenu.vue deleted file mode 100644 index 6fc0a7e..0000000 --- a/web/apps/web-ele/src/components/zq-draw/components/ContextMenu.vue +++ /dev/null @@ -1,436 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/zq-draw/components/DrawCanvas.vue b/web/apps/web-ele/src/components/zq-draw/components/DrawCanvas.vue deleted file mode 100644 index e9f0deb..0000000 --- a/web/apps/web-ele/src/components/zq-draw/components/DrawCanvas.vue +++ /dev/null @@ -1,65 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/zq-draw/components/DrawToolbar.vue b/web/apps/web-ele/src/components/zq-draw/components/DrawToolbar.vue deleted file mode 100644 index 92ccd7a..0000000 --- a/web/apps/web-ele/src/components/zq-draw/components/DrawToolbar.vue +++ /dev/null @@ -1,104 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/zq-draw/components/HyperlinkPopup.vue b/web/apps/web-ele/src/components/zq-draw/components/HyperlinkPopup.vue deleted file mode 100644 index 8f8f91f..0000000 --- a/web/apps/web-ele/src/components/zq-draw/components/HyperlinkPopup.vue +++ /dev/null @@ -1,141 +0,0 @@ - - - diff --git a/web/apps/web-ele/src/components/zq-draw/components/MainMenu.vue b/web/apps/web-ele/src/components/zq-draw/components/MainMenu.vue deleted file mode 100644 index 801ccba..0000000 --- a/web/apps/web-ele/src/components/zq-draw/components/MainMenu.vue +++ /dev/null @@ -1,336 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/zq-draw/components/PropertyPanel.vue b/web/apps/web-ele/src/components/zq-draw/components/PropertyPanel.vue deleted file mode 100644 index 115ff40..0000000 --- a/web/apps/web-ele/src/components/zq-draw/components/PropertyPanel.vue +++ /dev/null @@ -1,972 +0,0 @@ - - - - - diff --git a/web/apps/web-ele/src/components/zq-draw/components/StatsPanel.vue b/web/apps/web-ele/src/components/zq-draw/components/StatsPanel.vue deleted file mode 100644 index e19bce2..0000000 --- a/web/apps/web-ele/src/components/zq-draw/components/StatsPanel.vue +++ /dev/null @@ -1,230 +0,0 @@ - - - diff --git a/web/apps/web-ele/src/components/zq-draw/components/TextEditor.vue b/web/apps/web-ele/src/components/zq-draw/components/TextEditor.vue deleted file mode 100644 index 17547c5..0000000 --- a/web/apps/web-ele/src/components/zq-draw/components/TextEditor.vue +++ /dev/null @@ -1,356 +0,0 @@ - - -