From 8695eee8c8f07092bed1f23680e22a2869763c5e Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Thu, 6 Aug 2026 19:03:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 + pnpm-lock.yaml | 16 + src/main.ts | 7 +- .../components/CustomerBillingRulesPanel.vue | 1 + src/modules/customers/pages/CustomersView.vue | 22 +- .../downloads/pages/DownloadCenterView.vue | 14 +- .../carrier-rates/pages/CarrierRatesView.vue | 12 +- .../PlatformFirstLegOrdersPanel.vue | 8 +- src/modules/iam/pages/InternalUsersView.vue | 9 +- src/modules/iam/pages/PermissionsView.vue | 14 +- src/modules/iam/pages/RolesView.vue | 12 +- .../inbounds/pages/InboundOrdersView.vue | 31 +- .../counterparties/pages/PartnersView.vue | 9 +- .../pages/ExpressCompaniesView.vue | 10 +- .../unified-orders/api/unifiedOrders.test.ts | 7 + .../unified-orders/api/unifiedOrders.ts | 45 ++ .../pages/UnifiedOrdersView.test.ts | 13 + .../pages/UnifiedOrdersView.vue | 402 ++++++++++++++---- .../locations/pages/LocationsView.vue | 11 +- .../pallets/pages/PalletsView.vue | 13 +- .../warehouses/pages/WarehousesView.vue | 11 +- src/shared/components/DataTable.test.ts | 62 ++- src/shared/components/DataTable.vue | 150 ++++++- .../components/LayoutPreferenceList.vue | 116 +++++ src/shared/components/QueryToolbar.test.ts | 63 +++ src/shared/components/QueryToolbar.vue | 87 +++- src/shared/utils/uiLayoutPreference.test.ts | 33 ++ src/shared/utils/uiLayoutPreference.ts | 82 ++++ 28 files changed, 1100 insertions(+), 162 deletions(-) create mode 100644 src/shared/components/LayoutPreferenceList.vue create mode 100644 src/shared/components/QueryToolbar.test.ts create mode 100644 src/shared/utils/uiLayoutPreference.test.ts create mode 100644 src/shared/utils/uiLayoutPreference.ts diff --git a/package.json b/package.json index 0613f286..a7d055b2 100644 --- a/package.json +++ b/package.json @@ -16,11 +16,13 @@ "axios": "^1.18.1", "element-plus": "^2.14.3", "pinia": "^4.0.2", + "sortablejs": "^1.15.7", "vue": "^3.5.40", "vue-router": "^5.2.0" }, "devDependencies": { "@types/node": "^24.10.0", + "@types/sortablejs": "^1.15.9", "@vitejs/plugin-vue": "^6.0.8", "@vue/test-utils": "^2.4.11", "jsdom": "^29.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 53a31cc7..f9855f2d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: pinia: specifier: ^4.0.2 version: 4.0.2(@vue/devtools-api@8.2.1)(typescript@5.9.3)(vue@3.5.40(typescript@5.9.3)) + sortablejs: + specifier: ^1.15.7 + version: 1.15.7 vue: specifier: ^3.5.40 version: 3.5.40(typescript@5.9.3) @@ -33,6 +36,9 @@ importers: '@types/node': specifier: ^24.10.0 version: 24.13.3 + '@types/sortablejs': + specifier: ^1.15.9 + version: 1.15.9 '@vitejs/plugin-vue': specifier: ^6.0.8 version: 6.0.8(vite@8.1.5(@types/node@24.13.3)(yaml@2.9.0))(vue@3.5.40(typescript@5.9.3)) @@ -361,6 +367,9 @@ packages: '@types/node@24.13.3': resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} + '@types/sortablejs@1.15.9': + resolution: {integrity: sha512-7HP+rZGE2p886PKV9c9OJzLBI6BBJu1O7lJGYnPyG3fS4/duUCcngkNCjsLwIMV+WMqANe3tt4irrXHSIe68OQ==} + '@types/web-bluetooth@0.0.21': resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} @@ -1073,6 +1082,9 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + sortablejs@1.15.7: + resolution: {integrity: sha512-Kk8wLQPlS+yi1ZEf48a4+fzHa4yxjC30M/Sr2AnQu+f/MPwvvX9XjZ6OWejiz8crBsLwSq8GHqaxaET7u6ux0A==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -1638,6 +1650,8 @@ snapshots: dependencies: undici-types: 7.18.2 + '@types/sortablejs@1.15.9': {} + '@types/web-bluetooth@0.0.21': {} '@vitejs/plugin-vue@6.0.8(vite@8.1.5(@types/node@24.13.3)(yaml@2.9.0))(vue@3.5.40(typescript@5.9.3))': @@ -2360,6 +2374,8 @@ snapshots: signal-exit@4.1.0: {} + sortablejs@1.15.7: {} + source-map-js@1.2.1: {} stackback@0.0.2: {} diff --git a/src/main.ts b/src/main.ts index 17ffb0e5..4c269445 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,4 @@ -import { createApp } from 'vue' +import { computed, createApp } from 'vue' import { createPinia } from 'pinia' import { ElMessage } from 'element-plus' import 'element-plus/es/components/message/style/css' @@ -11,6 +11,7 @@ import { useUnsavedWorkStore } from '@/core/unsaved-work/unsavedWork' import { useWorkspaceTabsStore } from '@/core/workspace-tabs/workspaceTabs' import { useAuthStore } from '@/core/auth/auth' import { registerAuthSessionExpiredHandler } from '@/shared/api/http' +import { UI_PREFERENCE_SCOPE } from '@/shared/utils/uiLayoutPreference' import './styles/index.css' const pinia = createPinia() @@ -41,4 +42,6 @@ window.addEventListener('beforeunload', (event) => { event.returnValue = '' }) -createApp(App).use(pinia).use(router).mount('#app') +const app = createApp(App) +app.provide(UI_PREFERENCE_SCOPE, computed(() => auth.user?.id || 'anonymous')) +app.use(pinia).use(router).mount('#app') diff --git a/src/modules/customers/components/CustomerBillingRulesPanel.vue b/src/modules/customers/components/CustomerBillingRulesPanel.vue index 7bbed83e..812e2839 100644 --- a/src/modules/customers/components/CustomerBillingRulesPanel.vue +++ b/src/modules/customers/components/CustomerBillingRulesPanel.vue @@ -248,6 +248,7 @@ onMounted(loadRules) v-model:page-size="pageSize" :data="pagedRules" :columns="columns" + preference-key="customer-billing-rules-table" :loading="loading" :total="rules.length" :page-sizes="[10, 20, 50]" diff --git a/src/modules/customers/pages/CustomersView.vue b/src/modules/customers/pages/CustomersView.vue index 2eca6ddb..24c3baed 100644 --- a/src/modules/customers/pages/CustomersView.vue +++ b/src/modules/customers/pages/CustomersView.vue @@ -90,8 +90,8 @@ const qualificationPreviewKind = ref<'image' | 'pdf' | ''>('') const filters = ref({ keyword: '', status: '' }) const queryFields: QueryField[] = [ - { key: 'keyword', type: 'input', placeholder: '公司名称、客户ID或联系人' }, - { key: 'status', type: 'select', placeholder: '全部状态', options: [ + { key: 'keyword', type: 'input', label: '客户关键词', placeholder: '公司名称、客户ID或联系人' }, + { key: 'status', type: 'select', label: '状态', placeholder: '全部状态', options: [ { label: '待完善', value: 'PROFILE_REQUIRED' }, { label: '待审核', value: 'PENDING' }, { label: '启用', value: 'ACTIVE' }, { label: '已驳回', value: 'REJECTED' }, { label: '已停用', value: 'DISABLED' }, @@ -155,16 +155,16 @@ const unifiedSocialCreditCodePattern = /^[0-9A-Z]{18}$/ const customerColumns: DataTableColumn[] = [ { key: 'actions', label: '操作', minWidth: 190, slotName: 'actions' }, - { prop: 'tenantCode', label: '客户ID', minWidth: 170 }, + { key: 'tenantCode', prop: 'tenantCode', label: '客户ID', minWidth: 170 }, { key: 'company', label: '公司名称', minWidth: 230, slotName: 'company' }, - { prop: 'unifiedSocialCreditCode', label: '统一社会信用代码', minWidth: 205, formatter: (row: PlatformTenantResource) => displayText(row.unifiedSocialCreditCode) }, - { prop: 'contactName', label: '联系人', minWidth: 120, formatter: (row: PlatformTenantResource) => displayText(row.contactName) }, - { prop: 'contactPhone', label: '电话', minWidth: 150, formatter: (row: PlatformTenantResource) => displayText(row.contactPhone) }, - { prop: 'salesOwnerName', label: '销售人员', minWidth: 120, formatter: (row: PlatformTenantResource) => displayText(row.salesOwnerName) }, - { prop: 'paymentTermDays', label: '账期(天)', width: 105, formatter: (row: PlatformTenantResource) => row.paymentTermDays ?? 0 }, + { key: 'unifiedSocialCreditCode', prop: 'unifiedSocialCreditCode', label: '统一社会信用代码', minWidth: 205, formatter: (row: PlatformTenantResource) => displayText(row.unifiedSocialCreditCode) }, + { key: 'contactName', prop: 'contactName', label: '联系人', minWidth: 120, formatter: (row: PlatformTenantResource) => displayText(row.contactName) }, + { key: 'contactPhone', prop: 'contactPhone', label: '电话', minWidth: 150, formatter: (row: PlatformTenantResource) => displayText(row.contactPhone) }, + { key: 'salesOwnerName', prop: 'salesOwnerName', label: '销售人员', minWidth: 120, formatter: (row: PlatformTenantResource) => displayText(row.salesOwnerName) }, + { key: 'paymentTermDays', prop: 'paymentTermDays', label: '账期(天)', width: 105, formatter: (row: PlatformTenantResource) => row.paymentTermDays ?? 0 }, { key: 'status', label: '状态', width: 110, slotName: 'status' }, { key: 'orderCount', label: '运单数', width: 100, slotName: 'orderCount' }, - { prop: 'createdAt', label: '入驻时间', minWidth: 165, formatter: (row: PlatformTenantResource) => formatDate(row.createdAt) }, + { key: 'createdAt', prop: 'createdAt', label: '入驻时间', minWidth: 165, formatter: (row: PlatformTenantResource) => formatDate(row.createdAt) }, ] let loadSequence = 0 @@ -666,12 +666,12 @@ onMounted(async () => {