gaoluyang
2025-08-11 df1992a1c3ca982b1432aaf41668bb8437d02a2d
登录页联调开发,首页开发,销售台账开发,添加依赖
已修改7个文件
已添加6个文件
1796 ■■■■■ 文件已修改
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pnpm-lock.yaml 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue 补丁 | 查看 | 原始文档 | blame | 历史
src/api/salesManagement/invoiceLedger.js 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/salesManagement/invoiceRegistration.js 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/salesManagement/receiptPayment.js 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/salesManagement/salesLedger.js 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages.json 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index.vue 701 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/login.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/sales/salesAccount/detail.vue 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/sales/salesAccount/index.vue 392 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json
@@ -78,6 +78,7 @@
    "pinia": "2.2.2",
    "tslib": "^2.7.0",
    "uview-plus": "^3.4.62",
    "vant": "^4.9.21",
    "vue": "3.4.21",
    "vue-i18n": "^9.14.2"
  },
pnpm-lock.yaml
@@ -84,8 +84,11 @@
        specifier: ^2.7.0
        version: 2.7.0
      uview-plus:
        specifier: ^3.3.32
        version: 3.3.36
        specifier: ^3.4.62
        version: 3.4.84
      vant:
        specifier: ^4.9.21
        version: 4.9.21(vue@3.4.21(typescript@5.6.3))
      vue:
        specifier: 3.4.21
        version: 3.4.21(typescript@5.6.3)
@@ -1313,35 +1316,30 @@
    engines: {node: '>= 10.0.0'}
    cpu: [arm]
    os: [linux]
    libc: [glibc]
  '@parcel/watcher-linux-arm64-glibc@2.4.1':
    resolution: {integrity: sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==}
    engines: {node: '>= 10.0.0'}
    cpu: [arm64]
    os: [linux]
    libc: [glibc]
  '@parcel/watcher-linux-arm64-musl@2.4.1':
    resolution: {integrity: sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==}
    engines: {node: '>= 10.0.0'}
    cpu: [arm64]
    os: [linux]
    libc: [musl]
  '@parcel/watcher-linux-x64-glibc@2.4.1':
    resolution: {integrity: sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==}
    engines: {node: '>= 10.0.0'}
    cpu: [x64]
    os: [linux]
    libc: [glibc]
  '@parcel/watcher-linux-x64-musl@2.4.1':
    resolution: {integrity: sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==}
    engines: {node: '>= 10.0.0'}
    cpu: [x64]
    os: [linux]
    libc: [musl]
  '@parcel/watcher-win32-arm64@2.4.1':
    resolution: {integrity: sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==}
@@ -1401,55 +1399,46 @@
    resolution: {integrity: sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==}
    cpu: [arm]
    os: [linux]
    libc: [glibc]
  '@rollup/rollup-linux-arm-musleabihf@4.24.0':
    resolution: {integrity: sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==}
    cpu: [arm]
    os: [linux]
    libc: [musl]
  '@rollup/rollup-linux-arm64-gnu@4.24.0':
    resolution: {integrity: sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==}
    cpu: [arm64]
    os: [linux]
    libc: [glibc]
  '@rollup/rollup-linux-arm64-musl@4.24.0':
    resolution: {integrity: sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==}
    cpu: [arm64]
    os: [linux]
    libc: [musl]
  '@rollup/rollup-linux-powerpc64le-gnu@4.24.0':
    resolution: {integrity: sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==}
    cpu: [ppc64]
    os: [linux]
    libc: [glibc]
  '@rollup/rollup-linux-riscv64-gnu@4.24.0':
    resolution: {integrity: sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==}
    cpu: [riscv64]
    os: [linux]
    libc: [glibc]
  '@rollup/rollup-linux-s390x-gnu@4.24.0':
    resolution: {integrity: sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==}
    cpu: [s390x]
    os: [linux]
    libc: [glibc]
  '@rollup/rollup-linux-x64-gnu@4.24.0':
    resolution: {integrity: sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==}
    cpu: [x64]
    os: [linux]
    libc: [glibc]
  '@rollup/rollup-linux-x64-musl@4.24.0':
    resolution: {integrity: sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==}
    cpu: [x64]
    os: [linux]
    libc: [musl]
  '@rollup/rollup-win32-arm64-msvc@4.24.0':
    resolution: {integrity: sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==}
@@ -1520,6 +1509,14 @@
  '@uview-plus/types@3.2.5':
    resolution: {integrity: sha512-Zblby3WEN5d+NqS/UGs+1W5T55rs5zJw5eGKLUYoU5lKFm1arrlobbjA9/U481q68gBb7xA2775KKfk0FU5nnA==}
  '@vant/popperjs@1.3.0':
    resolution: {integrity: sha512-hB+czUG+aHtjhaEmCJDuXOep0YTZjdlRR+4MSmIFnkCQIxJaXLQdSsR90XWvAI2yvKUI7TCGqR8pQg2RtvkMHw==}
  '@vant/use@1.6.0':
    resolution: {integrity: sha512-PHHxeAASgiOpSmMjceweIrv2AxDZIkWXyaczksMoWvKV2YAYEhoizRuk/xFnKF+emUIi46TsQ+rvlm/t2BBCfA==}
    peerDependencies:
      vue: ^3.0.0
  '@vitejs/plugin-legacy@5.3.2':
    resolution: {integrity: sha512-8moCOrIMaZ/Rjln0Q6GsH6s8fAt1JOI3k8nmfX4tXUxE5KAExVctSyOBk+A25GClsdSWqIk2yaUthH3KJ2X4tg==}
@@ -1634,6 +1631,9 @@
  '@vue/shared@3.5.12':
    resolution: {integrity: sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==}
  '@vue/shared@3.5.18':
    resolution: {integrity: sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==}
  '@vue/tsconfig@0.5.1':
    resolution: {integrity: sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==}
@@ -3834,13 +3834,18 @@
    resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
    engines: {node: '>= 0.4.0'}
  uview-plus@3.3.36:
    resolution: {integrity: sha512-yiIIt3OkCDkBzflrr6by8qvYibvCzsFZ/Mn+Fdx9TDaTQAltWFBj7UNVN/wOeb3lou2T5S1QFy2rxw3OcAYi5g==}
    engines: {HBuilderX: ^3.1.0}
  uview-plus@3.4.84:
    resolution: {integrity: sha512-JIDgO3sIj3XmmbOAK1GefJt2NZHqDTYO8We/aNcyAml3QYXAq8HRIOdO66Vg+fjLwAkeH65X1IgKkYzwxM2xKQ==}
    engines: {HBuilderX: ^3.1.0, uni-app: ^4.66, uni-app-x: ''}
  v8-to-istanbul@8.1.1:
    resolution: {integrity: sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==}
    engines: {node: '>=10.12.0'}
  vant@4.9.21:
    resolution: {integrity: sha512-hXUoZMrLLjykimFRLDlGNd+K2iYSRh9YwLMKnsVdVZ+9inUKxpqnjhOqlZwocbnYkvJlS+febf9u9aJpDol4Pw==}
    peerDependencies:
      vue: ^3.0.0
  vary@1.1.2:
    resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
@@ -6225,6 +6230,12 @@
  '@uview-plus/types@3.2.5': {}
  '@vant/popperjs@1.3.0': {}
  '@vant/use@1.6.0(vue@3.4.21(typescript@5.6.3))':
    dependencies:
      vue: 3.4.21(typescript@5.6.3)
  '@vitejs/plugin-legacy@5.3.2(terser@5.34.1)(vite@5.2.8(@types/node@22.7.5)(less@4.2.0)(sass@1.79.5)(terser@5.34.1))':
    dependencies:
      '@babel/core': 7.25.8
@@ -6412,6 +6423,8 @@
  '@vue/shared@3.4.21': {}
  '@vue/shared@3.5.12': {}
  '@vue/shared@3.5.18': {}
  '@vue/tsconfig@0.5.1': {}
@@ -8882,7 +8895,7 @@
  utils-merge@1.0.1: {}
  uview-plus@3.3.36:
  uview-plus@3.4.84:
    dependencies:
      clipboard: 2.0.11
      dayjs: 1.11.13
@@ -8893,6 +8906,13 @@
      convert-source-map: 1.9.0
      source-map: 0.7.4
  vant@4.9.21(vue@3.4.21(typescript@5.6.3)):
    dependencies:
      '@vant/popperjs': 1.3.0
      '@vant/use': 1.6.0(vue@3.4.21(typescript@5.6.3))
      '@vue/shared': 3.5.18
      vue: 3.4.21(typescript@5.6.3)
  vary@1.1.2: {}
  vite@5.2.8(@types/node@22.7.5)(less@4.2.0)(sass@1.79.5)(terser@5.34.1):
src/App.vue
src/api/salesManagement/invoiceLedger.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,92 @@
// å¼€ç¥¨å°è´¦é¡µé¢æŽ¥å£
import request from '@/utils/request'
// åˆ†é¡µæŸ¥è¯¢
export function invoiceLedgerList(query) {
    return request({
        url: '/invoiceLedger/page',
        method: 'get',
        params: query
    })
}
// æ–°å¢ž
export function invoiceLedgerSaveOrUpdate(query) {
    return request({
        url: '/invoiceLedger/saveOrUpdate',
        method: 'post',
        data: query
    })
}
// å¼€ç¥¨å°è´¦åˆ é™¤
export function invoiceLedgerDel(query) {
    return request({
        url: '/invoiceLedger/del',
        method: 'delete',
        data: query
    })
}
// è¯¦æƒ…查询
export function invoiceLedgerDetail(query) {
    return request({
        url: '/invoiceLedger/info',
        method: 'get',
        params: query
    })
}
// é™„件提交
export function commitFile(query) {
    return request({
        url: '/invoiceLedger/commitFile',
        method: 'post',
        data: query
    })
}
// å¼€ç¥¨å°è´¦éƒ¨åˆ†ä¹ŸæŸ¥è¯¢
export function invoiceLedgerListNoPage(query) {
    return request({
        url: '/invoiceLedger/list',
        method: 'get',
        data: query
    })
}
// åˆ†é¡µæŸ¥è¯¢
export function invoiceLedgerSalesAccount(query) {
    return request({
        url: '/invoiceLedger/salesAccount',
        method: 'get',
        params: query
    })
}
// äº§å“å¼€ç¥¨è®°å½•分页查询
export function registrationProductPage(query) {
    return request({
        url: '/invoiceLedger/registrationProductPage',
        method: 'get',
        params: query
    })
}
// äº§å“å¼€ç¥¨è¯¦æƒ…查询
export function invoiceLedgerProductInfo(query) {
    return request({
        url: '/invoiceLedger/invoiceLedgerProductInfo',
        method: 'get',
        params: query
    })
}
export function delInvoiceLedgerByRegProductId(invoiceRegistrationProductId) {
    return request({
        url: '/invoiceLedger/delInvoiceLedger/'+ invoiceRegistrationProductId,
        method: 'delete'
    })
}
src/api/salesManagement/invoiceRegistration.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
// é”€å”®å°è´¦é¡µé¢æŽ¥å£
import request from '@/utils/request'
// åˆ†é¡µæŸ¥è¯¢
export function invoiceRegistrationList(query) {
    return request({
        url: '/invoiceRegistration/listPage',
        method: 'get',
        params: query
    })
}
// å¼€ç¥¨ç™»è®°æ–°å¢ž
export function invoiceRegistrationSave(query) {
    return request({
        url: '/invoiceRegistration/save',
        method: 'post',
        data: query
    })
}
// å¼€ç¥¨ç™»è®°åˆ é™¤
export function invoiceRegistrationDel(query) {
    return request({
        url: '/invoiceRegistration/del',
        method: 'delete',
        data: query
    })
}
// å­è¡¨æ ¼æŸ¥è¯¢
export function productList(query) {
    return request({
        url: '/invoiceRegistration/productList',
        method: 'get',
        params: query
    })
}
// å¼€ç¥¨ç™»è®°è¯¦æƒ…
export function invoiceRegistrationDetail(query) {
    return request({
        url: '/invoiceRegistration/detail',
        method: 'get',
        params: query
    })
}
// å¯¼å‡ºå¼€ç¥¨ç™»è®°
export function invoiceRegistrationExport(query) {
    return request({
        url: '/invoiceRegistration/export',
        method: 'get',
        params: query,
        responseType: 'blob'
    })
}
src/api/salesManagement/receiptPayment.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,84 @@
// å¼€ç¥¨ç™»è®°é¡µé¢æŽ¥å£
import request from '@/utils/request'
// æ–°å¢ž/修改
export function receiptPaymentSaveOrUpdate(query) {
    return request({
        url: '/receiptPayment/saveOrUpdate',
        method: 'post',
        data: query
    })
}
// å®¢æˆ·å¾€æ¥è®°å½•查询
export function customerInteractions(query) {
    return request({
        url: '/receiptPayment/customerInteractions',
        method: 'get',
        params: query
    })
}
// è¯¦æƒ…
export function receiptPaymentInfo(query) {
    return request({
        url: '/receiptPayment/info',
        method: 'get',
        params: query
    })
}
// åˆ é™¤
export function receiptPaymentDel(query) {
    return request({
        url: '/receiptPayment/del',
        method: 'delete',
        data: query
    })
}
// æŸ¥è¯¢å·²ç»ç»‘定发票的开票台账
export function bindInvoiceNoRegPage(query) {
    return request({
        url: '/receiptPayment/bindInvoiceNoRegPage',
        method: 'get',
        params: query
    })
}
// å¼€ç¥¨å°è´¦è¯¦æƒ…
export function invoiceInfo(query) {
    return request({
        url: '/receiptPayment/invoiceInfo',
        method: 'get',
        params: query
    })
}
// è¯¢å›žæ¬¾è®°å½•
export function receiptPaymentHistoryList(query) {
    return request({
        url: '/receiptPayment/receiptPaymentHistoryList',
        method: 'get',
        params: query
    })
}
/**
 * æŸ¥è¯¢å›žæ¬¾è®°å½•分页查询
 */
export function receiptPaymentHistoryListPage(query) {
    return request({
        url: '/receiptPayment/receiptPaymentHistoryListPage',
        method: 'get',
        params: query
    })
}
export function receiptPaymentHistoryListNoPage(query) {
    return request({
        url: '/receiptPayment/receiptPaymentHistoryListNoPage',
        method: 'get',
        params: query
    })
}
src/api/salesManagement/salesLedger.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,111 @@
// é”€å”®å°è´¦é¡µé¢æŽ¥å£
import request from "@/utils/request";
// åˆ†é¡µæŸ¥è¯¢
export function ledgerList(query) {
  return request({
    url: "/sales/ledger/list",
    method: "get",
    params: query,
  });
}
// å­è¡¨æ ¼æŸ¥è¯¢
export function productList(query) {
  return request({
    url: "/sales/product/list",
    method: "get",
    params: query,
  });
}
// æŸ¥è¯¢å®¢æˆ·åç§°åˆ—表
export function customerList(query) {
  return request({
    url: "/basic/customer/customerList",
    method: "get",
    params: query,
  });
}
// æ–°å¢žã€ä¿®æ”¹é”€å”®å°è´¦
export function addOrUpdateSalesLedger(query) {
  return request({
    url: "/sales/ledger/addOrUpdateSalesLedger",
    method: "post",
    data: query,
  });
}
// åˆ é™¤é”€å”®å°è´¦
export function delLedger(query) {
  return request({
    url: "/sales/ledger/delLedger",
    method: "delete",
    data: query,
  });
}
// æŸ¥è¯¢é”€å”®å°è´¦è¯¦æƒ…
export function getSalesLedgerWithProducts(query) {
  return request({
    url: "/sales/ledger/getSalesLedgerWithProducts",
    method: "get",
    params: query,
  });
}
// å®žæ—¶ä¿®æ”¹äº§å“ä¿¡æ¯
export function addOrUpdateSalesLedgerProduct(query) {
  return request({
    url: "/sales/product/addOrUpdateSalesLedgerProduct",
    method: "post",
    data: query,
  });
}
// åˆ é™¤äº§å“
export function delProduct(query) {
  return request({
    url: "/sales/product/delProduct",
    method: "delete",
    data: query,
  });
}
// ä¸Šä¼ é™„ä»¶
export function upload(query) {
  return request({
    url: "/file/upload",
    method: "post",
    data: query,
    responseType: "blob",
  });
}
// ç¼–辑时删除附件
export function delLedgerFile(query) {
  return request({
    url: "/sales/ledger/delLedgerFile",
    method: "delete",
    data: query,
  });
}
// é”€å”®ä¸åˆ†é¡µæŸ¥è¯¢
export function ledgerListNoPage(query) {
  return request({
    url: "/sales/ledger/listNoPage",
    method: "get",
    params: query,
  });
}
// åˆ†é¡µæŸ¥è¯¢
export function ledgerListPage(query) {
  return request({
    url: "/sales/ledger/listPage",
    method: "get",
    params: query,
  });
}
// æ ¹æ®é”€å”®åˆåŒå·æŸ¥äº§å“ä¿¡æ¯
export function getProductInfoByContractNo(query) {
  return request({
    url: "/purchase/ledger/getProductBySalesNo",
    method: "get",
    params: query,
  });
}
src/main.js
@@ -2,6 +2,8 @@
import plugins from './plugins'
import store from './store'
import uviewPlus from 'uview-plus'
import Vant from 'vant';
import 'vant/lib/index.css';
import { createSSRApp } from 'vue'
@@ -17,6 +19,7 @@
  app.use(store)
  app.use(uviewPlus)
  app.use(plugins)
  app.use(Vant)
  // #ifndef MP-WEIXIN
  // å¾®ä¿¡å°ç¨‹åºä¸­ä¸æ”¯æŒè‡ªå®šä¹‰æŒ‡ä»¤
src/pages.json
@@ -50,6 +50,20 @@
      }
    },
    {
      "path": "pages/sales/salesAccount/index",
      "style": {
        "navigationBarTitleText": "销售台账",
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/sales/salesAccount/detail",
      "style": {
        "navigationBarTitleText": "台账详情",
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/common/webview/index",
      "style": {
        "navigationBarTitleText": "浏览网页"
src/pages/index.vue
@@ -1,43 +1,155 @@
<template>
  <view class="content">
        <view>
        <view class="header-section">
            <view class="currentFactory">
                <up-text type="primary" :text="userStore.currentFactoryName" @click="show = true"
                <up-text type="primary" :text="userStore.currentFactoryName" @click="show = true" size="18"
                                 class="factoryName" suffixIcon="arrow-right" :iconStyle="iconStyle"></up-text>
            </view>
            <up-picker :show="show" :columns="factoryList" @confirm="changeFactory"></up-picker>
            <view>
                <view class="bg-img"></view>
            </view>
        <view class="hero-section">
            <view class="bg-img">
                <view class="hero-content">
                    <text class="hero-title">产品库存管理系统</text>
                </view>
            </view>
        </view>
        <view class="notice-section">
            <view class="notice">
                <view class="notice-content">
                    <view class="notice-left">
                        <text class="notice-status">📊 å®žæ—¶ç›‘控</text>
                    </view>
                    <view class="notice-separator"></view>
                    <view class="notice-right">
                        <text class="notice-label">{{currentStatus}}</text>
                        <text class="notice-text">当日销售设备数:<text class="notice-number">{{number}}<text class="notice-unit">个</text></text></text>
                    </view>
                </view>
            </view>
        </view>
        <!-- è¥é”€ç®¡ç†æ¨¡å— -->
        <view class="common-module marketing-module">
            <view class="module-header">
                <view class="module-title-container">
                    <text class="module-title">营销管理</text>
                </view>
            </view>
            <view class="module-content">
                <up-grid
                    :border="false"
                    col="4"
                >
                    <up-grid-item
                        v-for="(listItem,listIndex) in list"
                        :key="listIndex"
                        v-for="(item, index) in marketingItems"
                        :key="index"
                        @click="handleCommonItemClick(item)"
                    >
                        <view class="icon-container" :style="{ background: item.bgColor }">
                        <up-icon
                            :customStyle="{paddingTop:20+'rpx'}"
                            :name="listItem.name"
                            :size="22"
                                :name="item.icon"
                                :size="26"
                                color="#ffffff"
                        ></up-icon>
                        <text class="grid-text">{{listItem.title}}</text>
                        </view>
                        <text class="item-label">{{item.label}}</text>
                    </up-grid-item>
                </up-grid>
            </view>
        </view>
<!--        <view class="select-container">-->
<!--            <up-picker-data-->
<!--                class="picker"-->
<!--                v-model="currentFatoryId"-->
<!--                title="请选择公司"-->
<!--                :options="factoryList"-->
<!--                valueKey="id"-->
<!--                labelKey="name">-->
<!--            </up-picker-data>-->
<!--        </view>-->
        <!-- é‡‡è´­ç®¡ç†æ¨¡å— -->
        <view class="common-module purchase-module">
            <view class="module-header">
                <view class="module-title-container">
                    <text class="module-title">采购管理</text>
                </view>
            </view>
            <view class="module-content">
                <up-grid
                    :border="false"
                    col="4"
                >
                    <up-grid-item
                        v-for="(item, index) in purchaseItems"
                        :key="index"
                        @click="handleCommonItemClick(item)"
                    >
                        <view class="icon-container" :style="{ background: item.bgColor }">
                            <up-icon
                                :name="item.icon"
                                :size="26"
                                color="#ffffff"
                            ></up-icon>
                        </view>
                        <text class="item-label">{{item.label}}</text>
                    </up-grid-item>
                </up-grid>
            </view>
        </view>
        <!-- ååŒåŠžå…¬æ¨¡å— -->
        <view class="common-module collaboration-module">
            <view class="module-header">
                <view class="module-title-container">
                    <text class="module-title">协同办公</text>
                </view>
            </view>
            <view class="module-content">
                <up-grid
                    :border="false"
                    col="4"
                >
                    <up-grid-item
                        v-for="(item, index) in collaborationItems"
                        :key="index"
                        @click="handleCommonItemClick(item)"
                    >
                        <view class="icon-container" :style="{ background: item.bgColor }">
                            <up-icon
                                :name="item.icon"
                                :size="26"
                                color="#ffffff"
                            ></up-icon>
                        </view>
                        <text class="item-label">{{item.label}}</text>
                    </up-grid-item>
                </up-grid>
            </view>
        </view>
        <!-- è®¾å¤‡ç®¡ç†æ¨¡å— -->
        <view class="common-module equipment-module">
            <view class="module-header">
                <view class="module-title-container">
                    <text class="module-title">设备管理</text>
                </view>
            </view>
            <view class="module-content">
                <up-grid
                    :border="false"
                    col="4"
                >
                    <up-grid-item
                        v-for="(item, index) in equipmentItems"
                        :key="index"
                        @click="handleCommonItemClick(item)"
                    >
                        <view class="icon-container" :style="{ background: item.bgColor }">
                            <up-icon
                                :name="item.icon"
                                :size="26"
                                color="#ffffff"
                            ></up-icon>
                        </view>
                        <text class="item-label">{{item.label}}</text>
                    </up-grid-item>
                </up-grid>
            </view>
        </view>
  </view>
</template>
@@ -53,36 +165,142 @@
const factoryList = ref([]);
const factoryListTem = ref([]);
const iconStyle = {
    fontSize: '14px',
    color: '#165DFF'
    fontSize: '18px',
    color: '#2979ff'
}
// åˆ›å»ºå“åº”式数据
const list = reactive([
// é€šçŸ¥çŠ¶æ€åˆ‡æ¢
const statusList = ['销售', '采购']
let statusIndex = 0
const currentStatus = ref(statusList[0])
const number = ref(7643)
// å®šæ—¶å™¨åˆ‡æ¢é€šçŸ¥çŠ¶æ€
const startStatusTimer = () => {
    setInterval(() => {
        statusIndex = (statusIndex + 1) % statusList.length
        currentStatus.value = statusList[statusIndex]
    }, 3000)
}
// è¥é”€ç®¡ç†åŠŸèƒ½æ•°æ®
const marketingItems = reactive([
    {
        name: 'photo',
        title: '图片'
        icon: 'account',
        label: '销售台账',
        bgColor: '#2979ff'
    },
    {
        name: 'lock',
        title: '锁头'
        icon: 'home',
        label: '开票登记',
        bgColor: '#1976d2'
    },
    {
        name: 'star',
        title: '星星'
        icon: 'file-text',
        label: '开票台账',
        bgColor: '#42a5f5'
    },
    {
        name: 'hourglass',
        title: '沙漏'
        icon: 'shopping-cart',
        label: '回款登记',
        bgColor: '#64b5f6'
    },
    {
        name: 'home',
        title: '首页'
        icon: 'chat',
        label: '回款流水',
        bgColor: '#90caf9'
    },
    {
        name: 'volume', // æ³¨æ„ï¼šè¿™é‡Œä¿®æ”¹äº† name ä»Ž 'star' æ”¹ä¸º 'volume',以避免列表中两个元素具有相同的 name
        title: '音量'
        icon: 'chat',
        label: '客户往来',
        bgColor: '#90caf9'
    }
]);
// é‡‡è´­ç®¡ç†åŠŸèƒ½æ•°æ®
const purchaseItems = reactive([
    {
        icon: 'order',
        label: '采购台账',
        bgColor: '#bbdefb'
    },
    {
        icon: 'truck',
        label: '来票登记',
        bgColor: '#e3f2fd'
    },
    {
        icon: 'box',
        label: '来票台账',
        bgColor: '#f3e5f5'
    },
    {
        icon: 'chart-line',
        label: '付款登记',
        bgColor: '#e8eaf6'
    },
    {
        icon: 'settings',
        label: '付款流水',
        bgColor: '#f1f8e9'
    },
    {
        icon: 'settings',
        label: '供应商往来',
        bgColor: '#f1f8e9'
    },
]);
// ååŒåŠžå…¬åŠŸèƒ½æ•°æ®
const collaborationItems = reactive([
    {
        icon: 'checkmark-circle',
        label: '协同审批',
        bgColor: '#4caf50'
    },
    {
        icon: 'map-pin',
        label: '客户拜访',
        bgColor: '#ff9800'
    }
]);
// è®¾å¤‡ç®¡ç†åŠŸèƒ½æ•°æ®
const equipmentItems = reactive([
    {
        icon: 'list',
        label: '设备台账',
        bgColor: '#9c27b0'
    },
    {
        icon: 'wrench',
        label: '设备报修',
        bgColor: '#f44336'
    },
    {
        icon: 'shield-check',
        label: '设备保养',
        bgColor: '#00bcd4'
    }
]);
// å¤„理常用功能点击
const handleCommonItemClick = (item) => {
    // æ ¹æ®ä¸åŒçš„功能项进行跳转
    switch (item.label) {
        case '销售台账':
            uni.navigateTo({
                url: '/pages/sales/salesAccount/index'
            });
            break;
        default:
            uni.showToast({
                title: `点击了${item.label}`,
                icon: 'none'
            });
    }
};
// åˆ›å»ºå¯¹å­ç»„件的引用
const uToastRef = ref(null);
@@ -140,34 +358,421 @@
    // è®¾ç½®ç”¨æˆ·ä¿¡æ¯
    userStore.getInfo()
    getUserLoginFacotryList()
    // å¯åŠ¨é€šçŸ¥çŠ¶æ€å®šæ—¶å™¨
    startStatusTimer()
});
</script>
<style scoped lang="scss">
.content {
    background-color: transparent !important;
    padding: 14px;
    background: linear-gradient(135deg, #f8f9fa 0%, #e3f2fd 100%);
    min-height: 100vh;
    padding: 20px;
    padding-top: env(safe-area-inset-top);
    position: relative;
    &::before {
        content: '';
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="dots" width="20" height="20" patternUnits="userSpaceOnUse"><circle cx="10" cy="10" r="1" fill="rgba(41, 121, 255, 0.03)"/></pattern></defs><rect width="100" height="100" fill="url(%23dots)"/></svg>');
        pointer-events: none;
        z-index: -1;
}
    &::after {
        content: '';
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: radial-gradient(circle at 20% 80%, rgba(41, 121, 255, 0.02) 0%, transparent 50%),
                    radial-gradient(circle at 80% 20%, rgba(156, 39, 176, 0.02) 0%, transparent 50%);
        pointer-events: none;
        z-index: -1;
    }
}
/* æœ¬é¡µä¸å†å®šä¹‰ .safe-area-top,已移至全局样式 */
.header-section {
    margin-bottom: 16px;
    animation: fadeInDown 0.6s ease-out;
}
.currentFactory {
    margin-top: 12px;
    margin-left: 6px;
    font-weight: 400;
    font-size: 14px;
    margin-top: 8px;
    margin-left: 4px;
    font-weight: 500;
    display: flex;
}
.factoryName {
    width: auto;
}
:deep(.u-text) {
    align-items: flex-end;
    align-items: center;
}
.hero-section {
    margin-bottom: 16px;
    animation: fadeInUp 0.6s ease-out 0.1s both;
}
.bg-img {
    margin-top: 12px;
    width: 100%;
    height: 145px;
    background-color: #ffffff;
    border-radius: 10px 10px 10px 10px;
    height: 120px;
    background: linear-gradient(135deg, #2979ff 0%, #1565c0 100%);
    border-radius: 12px;
    position: relative;
    overflow: hidden;
    box-shadow: 0 4px 20px rgba(41, 121, 255, 0.15);
    &::before {
        content: '';
        position: absolute;
        top: -50%;
        left: -50%;
        width: 200%;
        height: 200%;
        background: conic-gradient(from 0deg, transparent, rgba(255,255,255,0.1), transparent, rgba(255,255,255,0.05), transparent);
        animation: rotate 20s linear infinite;
}
    &::after {
        content: '';
        position: absolute;
        top: 0;
        right: 0;
        width: 120px;
        height: 120px;
        background: radial-gradient(circle, rgba(255,255,255,0.15) 0%, transparent 70%);
        border-radius: 50%;
        transform: translate(40px, -40px);
    }
}
.hero-content {
    position: relative;
    z-index: 1;
    padding: 20px;
    height: 100%;
    display: flex;
    align-items: center;
}
.hero-title {
    color: #ffffff;
    font-size: 24px;
    font-weight: 600;
}
.notice-section {
    margin-bottom: 16px;
    animation: fadeInUp 0.6s ease-out 0.2s both;
}
.notice {
    width: 100%;
    background: linear-gradient(135deg, #EAF2FF 0%, #BBDEFB 100%);
    border: 1px solid #e3f2fd;
    border-radius: 12px;
    padding: 16px;
    box-shadow: 0 4px 20px rgba(41, 121, 255, 0.08);
    position: relative;
    overflow: hidden;
    &::before {
        content: '';
        position: absolute;
        top: -50%;
        left: -50%;
        width: 200%;
        height: 200%;
        background: linear-gradient(45deg, transparent, rgba(255,255,255,0.6), transparent);
        animation: shine 4s infinite;
    }
    &::after {
        content: '';
        position: absolute;
        top: 0;
        right: 0;
        width: 80px;
        height: 80px;
        background: radial-gradient(circle, rgba(255,255,255,0.2) 0%, transparent 70%);
        border-radius: 50%;
        transform: translate(30px, -30px);
    }
}
@keyframes shine {
    0% {
        transform: translateX(-100%) translateY(-100%) rotate(45deg);
    }
    100% {
        transform: translateX(100%) translateY(100%) rotate(45deg);
    }
}
@keyframes fadeInDown {
    from {
        opacity: 0;
        transform: translateY(-20px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}
@keyframes fadeInUp {
    from {
        opacity: 0;
        transform: translateY(20px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}
@keyframes rotate {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}
.notice-content {
    display: flex;
    align-items: center;
    height: 100%;
    position: relative;
    z-index: 1;
}
.notice-left {
    margin-right: 16px;
}
.notice-status {
    font-weight: 600;
    font-size: 16px;
    color: #1976d2;
}
.notice-separator {
    width: 1px;
    height: 24px;
    background: #e0e0e0;
    margin-right: 16px;
}
.notice-right {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex: 1;
}
.notice-label {
    color: #1976d2;
    font-size: 14px;
    font-weight: 500;
    margin-right: 12px;
}
.notice-text {
    font-weight: 400;
    font-size: 14px;
    color: #666666;
}
.notice-number {
    font-weight: 600;
    font-size: 16px;
    color: #1976d2;
    margin-left: 4px;
}
.notice-unit {
    color: #666666;
    font-size: 14px;
    margin-left: 2px;
}
/* åŠŸèƒ½æ¨¡å—æ ·å¼ */
.common-module {
    margin-bottom: 24px;
    background: linear-gradient(135deg, #ffffff 0%, #fafbfc 100%);
    border-radius: 16px;
    padding: 16px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.06);
    border: none;
    position: relative;
    overflow: hidden;
    transition: all 0.3s ease;
    &::after {
        content: '';
        position: absolute;
        top: 0;
        right: 0;
        width: 60px;
        height: 60px;
        background: radial-gradient(circle, rgba(0,0,0,0.02) 0%, transparent 70%);
        border-radius: 50%;
        transform: translate(30px, -30px);
    }
    &:hover {
        transform: translateY(-2px);
        box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1);
        &::after {
            background: radial-gradient(circle, rgba(0,0,0,0.04) 0%, transparent 70%);
        }
    }
}
.marketing-module {
    --module-color: #2979ff;
}
.purchase-module {
    --module-color: #1976d2;
}
.collaboration-module {
    --module-color: #4caf50;
}
.equipment-module {
    --module-color: #9c27b0;
}
.module-header {
    margin-bottom: 24px;
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.module-title-container {
    display: flex;
    align-items: center;
}
.module-title {
    color: #333333;
    font-size: 18px;
    font-weight: 600;
    position: relative;
    &::after {
        content: '';
        position: absolute;
        bottom: -4px;
        left: 0;
        width: 100%;
        height: 2px;
        background: linear-gradient(90deg, var(--module-color), rgba(255,255,255,0.9));
        border-radius: 1px;
        transition: all 0.3s ease;
        box-shadow: 0 0 8px rgba(0,0,0,0.1);
    }
    &:hover::after {
        width: 30px;
        box-shadow: 0 0 12px rgba(0,0,0,0.15);
    }
}
.module-subtitle {
    color: #666666;
    font-size: 12px;
    font-weight: 400;
    margin-left: 8px;
}
.module-content {
    width: 100%;
    display: grid;
    gap: 16px;
}
.icon-container {
    width: 52px;
    height: 52px;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 6px;
    box-shadow: 0 3px 12px rgba(0, 0, 0, 0.12);
    transition: all 0.3s ease;
    position: relative;
    overflow: hidden;
    &::before {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, transparent 50%, rgba(255,255,255,0.05) 100%);
        opacity: 0;
        transition: opacity 0.3s ease;
    }
    &::after {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        border-radius: 12px;
        background: linear-gradient(45deg, transparent, rgba(255,255,255,0.2), transparent);
        opacity: 0;
        transition: opacity 0.3s ease;
    }
    &:hover {
        transform: translateY(-3px) scale(1.02);
        box-shadow: 0 8px 25px rgba(0, 0, 0, 0.18);
        &::before,
        &::after {
            opacity: 1;
        }
    }
}
.item-label {
    font-size: 13px;
    color: #555555;
    text-align: center;
    display: block;
    line-height: 1.4;
    font-weight: 500;
    margin-top: 4px;
    margin-bottom: 10px;
}
.grid-text {
    font-size: 14px;
    color: #909399;
@@ -176,4 +781,6 @@
    box-sizing: border-box;
    /* #endif */
}
</style>
src/pages/login.vue
@@ -1,8 +1,6 @@
<template>
  <view class="normal-login-container">
    <view class="logo-content">
<!--      <image style="width: 100rpx;height: 100rpx;" :src="globalConfig.appInfo.logo" mode="widthFix">-->
<!--      </image>-->
      <text>账号密码登录</text>
    </view>
    <view class="login-form-content">
@@ -171,9 +169,10 @@
.normal-login-container {
  width: 100%;
    height: 100vh;
  .logo-content {
    width: 100%;
    width: 90%;
        font-weight: 400;
        font-size: 30px;
        color: #333333;
src/pages/sales/salesAccount/detail.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,279 @@
<template>
  <view class="account-detail">
    <!-- é¡¶éƒ¨æ ‡é¢˜æ  -->
    <view class="header">
      <up-icon name="arrow-left" size="20" color="#333" @click="goBack" />
      <text class="title">台账详情</text>
    </view>
    <!-- è¡¨å•区域 -->
    <view class="form-section">
      <van-form ref="formRef" :modelValue="form" :rules="rules" label-width="100px" input-align="right">
        <van-field label="销售合同号" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="请输入销售合同号">
        </van-field>
                <van-field label="销售合同号" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="请输入销售合同号">
                </van-field>
                <van-field label="销售合同号" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="请输入销售合同号">
                </van-field>
                <van-field label="销售合同号" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="请输入销售合同号">
                </van-field>
                <van-field label="销售合同号" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="请输入销售合同号">
                </van-field>
                <van-field label="销售合同号" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="请输入销售合同号">
                </van-field>
                <van-field label="录入人" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="请输入" readonly>
                </van-field>
                <van-field label="录入日期" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="请输入" readonly>
                </van-field>
      </van-form>
    </view>
    <!-- äº§å“ä¿¡æ¯ -->
    <view class="product-section">
      <view class="section-header">
        <text class="section-title">产品信息</text>
        <button class="add-btn" @click="addProduct">新增</button>
      </view>
      <view class="product-card" v-for="(product, idx) in products" :key="idx">
        <view class="product-row">
          <text class="product-label">产品类</text>
          <uni-easyinput v-model="product.type" placeholder="请输入产品类" />
        </view>
        <view class="product-row">
          <text class="product-label">单位</text>
          <uni-easyinput v-model="product.unit" placeholder="请输入单位" />
          <text class="product-label">数量</text>
          <uni-easyinput v-model="product.amount" placeholder="请输入数量" type="number" />
        </view>
        <view class="product-row">
          <text class="product-label">税率</text>
          <uni-easyinput v-model="product.taxRate" placeholder="请输入税率" />
          <text class="product-label">含税单价</text>
          <uni-easyinput v-model="product.taxPrice" placeholder="请输入含税单价" />
        </view>
        <view class="product-row">
          <text class="product-label">含税总价</text>
          <uni-easyinput v-model="product.taxTotal" placeholder="请输入含税总价" />
          <text class="product-label">合同金额</text>
          <uni-easyinput v-model="product.contractAmount" placeholder="请输入合同金额" />
        </view>
        <view class="product-row">
          <text class="product-label">操作</text>
          <uni-easyinput v-model="product.operateDate" placeholder="请输入操作时间" />
        </view>
        <view class="product-row">
          <text class="product-label">备注</text>
          <uni-easyinput v-model="product.remark" placeholder="请输入备注" />
        </view>
        <view class="product-row del-row">
          <button class="del-btn" @click="removeProduct(idx)">删除</button>
        </view>
      </view>
    </view>
    <!-- åº•部按钮 -->
    <view class="footer-btns">
      <van-button class="cancel-btn" @click="goBack">取消</van-button>
      <van-button class="save-btn" @click="submitForm">保存</van-button>
    </view>
  </view>
</template>
<script setup>
import { ref } from 'vue';
const goBack = () => {
  uni.navigateBack();
};
const formRef = ref();
const paymentMethods = ['对公转账', '现金', '其他'];
const form = ref({
  salesContractNo: '',
  customerContract: '',
  projectName: '',
  contractAmount: '',
  executionDate: '',
  paymentMethod: '',
});
const rules = {
  salesContractNo: {
    rules: [{ required: true, errorMessage: '销售合同号不能为空' }]
  },
  customerContract: {
    rules: [{ required: true, errorMessage: '客户合同不能为空' }]
  },
  projectName: {
    rules: [{ required: true, errorMessage: '项目名称不能为空' }]
  },
  contractAmount: {
    rules: [{ required: true, errorMessage: '合同金额不能为空' }]
  },
  executionDate: {
    rules: [{ required: true, errorMessage: '签订日期不能为空' }]
  },
  paymentMethod: {
    rules: [{ required: true, errorMessage: '请选择付款方式' }]
  }
};
const products = ref([
  {
    type: 'LS-29911',
    unit: '周庄镇',
    amount: '86590905972612',
    taxRate: '这里是项目名称',
    taxPrice: '这里是项目名称',
    taxTotal: '这里是项目名称',
    contractAmount: '32011元',
    operateDate: '2022-02-22 11:30:50',
    remark: '',
  },
  {
    type: 'LS-29911',
    unit: '周庄镇',
    amount: '86590905972612',
    taxRate: '这里是项目名称',
    taxPrice: '这里是项目名称',
    taxTotal: '这里是项目名称',
    contractAmount: '32011元',
    operateDate: '2022-02-22 11:30:50',
    remark: '',
  },
]);
const addProduct = () => {
  products.value.push({
    type: '',
    unit: '',
    amount: '',
    taxRate: '',
    taxPrice: '',
    taxTotal: '',
    contractAmount: '',
    operateDate: '',
    remark: '',
  });
};
const removeProduct = (idx) => {
  products.value.splice(idx, 1);
};
const submitForm = () => {
  formRef.value.validate().then(() => {
    uni.showToast({ title: '保存成功', icon: 'success' });
  });
};
</script>
<style scoped lang="scss">
.account-detail {
  min-height: 100vh;
  background: #f8f9fa;
  padding-bottom: 80px;
}
.header {
  display: flex;
  align-items: center;
  background: #fff;
  padding: 16px 20px;
  border-bottom: 1px solid #f0f0f0;
  position: sticky;
  top: 0;
  z-index: 100;
}
.title {
  flex: 1;
  text-align: center;
  font-size: 18px;
  font-weight: 600;
  color: #333;
}
.form-section {
    margin-top: 16px;
}
.van-field {
    height: 56px;
    line-height: 36px;
}
.product-section {
  background: #fff;
  margin: 16px;
  border-radius: 16px;
  padding: 20px 16px 8px 16px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.04);
}
.section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}
.section-title {
  font-size: 16px;
  font-weight: 600;
  color: #333;
}
.add-btn {
  background: #2979ff;
  color: #fff;
  border-radius: 8px;
  padding: 4px 16px;
  font-size: 14px;
}
.product-card {
  background: #f8f9fa;
  border-radius: 12px;
  padding: 12px;
  margin-bottom: 16px;
  box-shadow: 0 1px 4px rgba(41,121,255,0.06);
  position: relative;
}
.product-row {
  display: flex;
  align-items: center;
  margin-bottom: 8px;
}
.product-label {
  min-width: 60px;
  color: #888;
  font-size: 13px;
}
.del-row {
  justify-content: flex-end;
}
.del-btn {
  background: #ff4d4f;
  color: #fff;
  border-radius: 8px;
  padding: 4px 16px;
  font-size: 13px;
  margin-top: 4px;
}
.footer-btns {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  background: #fff;
  display: flex;
  justify-content: space-around;
  align-items: center;
  padding: 12px 0;
  box-shadow: 0 -2px 8px rgba(0,0,0,0.05);
  z-index: 1000;
}
.cancel-btn {
    font-weight: 400;
    font-size: 16px;
    color: #FFFFFF;
    width: 102px;
    background: #C7C9CC;
    box-shadow: 0px 4px 10px 0px rgba(3,88,185,0.2);
    border-radius: 40px 40px 40px 40px;
}
.save-btn {
    font-weight: 400;
    font-size: 16px;
    color: #FFFFFF;
    width: 224px;
    background: linear-gradient( 140deg, #00BAFF 0%, #006CFB 100%);
    box-shadow: 0px 4px 10px 0px rgba(3,88,185,0.2);
    border-radius: 40px 40px 40px 40px;
}
</style>
src/pages/sales/salesAccount/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,392 @@
<template>
    <view class="sales-account">
        <!-- é¡µé¢å¤´éƒ¨ -->
        <view class="page-header">
            <view class="header-left">
                <up-icon name="arrow-left" size="20" color="#333" @click="goBack"></up-icon>
            </view>
            <view class="header-center">
                <text class="page-title">销售台账</text>
            </view>
        </view>
        <!-- æœç´¢å’Œç­›é€‰åŒºåŸŸ -->
        <view class="search-filter-section">
            <view class="search-bar">
                <view class="search-input">
                    <input
                        class="search-text"
                        placeholder="请输入销售合同号/客户名称"
                        v-model="searchKeyword"
                    />
                </view>
                <view class="filter-button" @click="getList">
                    <up-icon name="search" size="24" color="#999"></up-icon>
                </view>
            </view>
        </view>
        <!-- é”€å”®å°è´¦ç€‘布流 -->
        <view class="ledger-list" v-if="total > 0">
            <view v-for="(item, index) in ledgerList" :key="index">
                <view class="ledger-item" @click="handleItemClick(item)">
                    <view class="item-header">
                        <view class="item-left">
                            <view class="document-icon">
                                <up-icon name="file-text" size="16" color="#ffffff"></up-icon>
                            </view>
                            <text class="item-id">{{ item.salesContractNo }}</text>
                        </view>
                        <!--                            <view class="item-tag">-->
                        <!--                                <text class="tag-text">{{ item.recorder }}</text>-->
                        <!--                            </view>-->
                    </view>
                    <up-divider></up-divider>
                    <view class="item-details">
                        <view class="detail-row">
                            <text class="detail-label">客户名称</text>
                            <text class="detail-value">{{ item.customerName }}</text>
                        </view>
                        <view class="detail-row">
                            <text class="detail-label">客户合同号</text>
                            <text class="detail-value highlight">{{ item.customerContractNo }}</text>
                        </view>
                        <view class="detail-row">
                            <text class="detail-label">业务员</text>
                            <text class="detail-value">{{ item.salesman }}</text>
                        </view>
                        <view class="detail-row">
                            <text class="detail-label">项目名称</text>
                            <text class="detail-value">{{ item.projectName }}</text>
                        </view>
                        <view class="detail-row">
                            <text class="detail-label">付款方式</text>
                            <text class="detail-value">{{ item.paymentMethod }}</text>
                        </view>
                        <view class="detail-row">
                            <text class="detail-label">合同金额(元)</text>
                            <text class="detail-value highlight">{{ item.contractAmount }}</text>
                        </view>
                        <view class="detail-row">
                            <text class="detail-label">签订日期</text>
                            <text class="detail-value">{{ item.executionDate }}</text>
                        </view>
                        <up-divider></up-divider>
                        <view class="detail-info">
                            <view class="detail-row">
                                <text class="detail-label">录入人</text>
                                <text class="detail-value">{{ item.entryPersonName }}</text>
                            </view>
                            <view class="detail-row">
                                <text class="detail-label">录入日期</text>
                                <text class="detail-value">{{ item.entryDate }}</text>
                            </view>
                        </view>
                    </view>
                </view>
            </view>
        </view>
        <view v-else class="no-data">
            <text>暂无销售台账数据</text>
        </view>
        <!-- æµ®åŠ¨æ“ä½œæŒ‰é’® -->
        <view class="fab-button" @click="handleAdd">
            <up-icon name="plus" size="24" color="#ffffff"></up-icon>
        </view>
    </view>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import {ledgerListPage} from "@/api/salesManagement/salesLedger";
// æœç´¢å…³é”®è¯
const searchKeyword = ref('');
// é”€å”®å°è´¦æ•°æ®
const ledgerList = ref([]);
const total = ref(0);
// è¿”回上一页
const goBack = () => {
    uni.navigateBack();
};
// æŸ¥è¯¢åˆ—表
const getList = () => {
    const page = {
        current: -1,
        size: -1
    }
    ledgerListPage({...page}).then((res) => {
        ledgerList.value = res.records;
        total.value = res.total;
    }).catch(() => {
            // tableLoading.value = false;
    });
};
// æ˜¾ç¤ºç­›é€‰é€‰é¡¹
const showFilterOptions = () => {
    uni.showActionSheet({
        itemList: ['按日期筛选', '按状态筛选', '按金额筛选'],
        success: (res) => {
            console.log('选择了筛选选项:', res.tapIndex);
        }
    });
};
// ç‚¹å‡»åˆ—表项
const handleItemClick = (item) => {
    uni.showToast({
        title: `查看合同: ${item.contractId}`,
        icon: 'none'
    });
};
// æ·»åŠ æ–°è®°å½•
const handleAdd = () => {
  uni.navigateTo({
    url: '/pages/sales/salesAccount/detail'
  });
};
onMounted(() => {
    // é¡µé¢åŠ è½½å®ŒæˆåŽçš„åˆå§‹åŒ–é€»è¾‘
    getList()
});
</script>
<style scoped lang="scss">
.u-divider {
    margin: 0 !important;
}
.sales-account {
    min-height: 100vh;
    background: #f8f9fa;
    position: relative;
}
.page-header {
    background: #ffffff;
  padding: 16px 20px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid #f0f0f0;
    position: sticky;
  /* å…¼å®¹ iOS åˆ˜æµ·/灵动岛安全区 */
  padding-top: env(safe-area-inset-top);
  top: 0;
    z-index: 100;
}
.header-left {
    display: flex;
    align-items: center;
    gap: 8px;
}
.nav-icon {
    width: 24px;
    height: 24px;
    background: #2979ff;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.nav-text {
    font-size: 14px;
    color: #2979ff;
    font-weight: 500;
}
.header-center {
    flex: 1;
    text-align: center;
}
.page-title {
    font-size: 18px;
    font-weight: 600;
    color: #333;
}
.header-right {
    display: flex;
    align-items: center;
}
.status-bar {
    display: flex;
    align-items: center;
    gap: 4px;
}
.signal, .wifi, .battery {
    width: 16px;
    height: 8px;
    background: #333;
    border-radius: 2px;
}
.search-filter-section {
    padding: 10px 20px;
    background: #ffffff;
}
.search-bar {
    display: flex;
    align-items: center;
    gap: 12px;
}
.search-input {
    flex: 1;
    background: #f5f5f5;
    border-radius: 24px;
    padding: 10px 16px;
    display: flex;
    align-items: center;
    gap: 8px;
}
.search-text {
    flex: 1;
    font-size: 14px;
    color: #333;
    background: transparent;
    border: none;
    outline: none;
}
.search-text::placeholder {
    color: #999;
}
.filter-button {
    width: 40px;
    height: 40px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.ledger-list {
    padding: 20px;
}
.ledger-item {
    background: #ffffff;
    border-radius: 12px;
    margin-bottom: 16px;
    overflow: hidden;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
    padding: 0 16px;
}
.item-header {
    padding: 16px 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.item-left {
    display: flex;
    align-items: center;
    gap: 8px;
}
.document-icon {
    width: 24px;
    height: 24px;
    background: #2979ff;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.item-id {
    font-size: 14px;
    color: #333;
    font-weight: 500;
}
.item-tag {
    background: #4caf50;
    border-radius: 4px;
    padding: 2px 4px;
}
.tag-text {
    font-size: 11px;
    color: #ffffff;
    font-weight: 500;
}
.item-details {
    padding: 16px 0;
}
.detail-row {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    margin-bottom: 8px;
    &:last-child {
        margin-bottom: 0;
    }
}
.detail-info {
    margin-top: 10px;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
}
.detail-label {
    font-size: 12px;
    color: #777777;
    min-width: 60px;
}
.detail-value {
    font-size: 12px;
    color: #000000;
    text-align: right;
    flex: 1;
    margin-left: 16px;
}
.detail-value.highlight {
    color: #2979ff;
    font-weight: 500;
}
.no-data {
    padding: 40px 0;
    text-align: center;
    color: #999;
}
.fab-button {
    position: fixed;
    bottom: 30px;
    right: 30px;
    width: 56px;
    height: 56px;
    background: #2979ff;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 16px rgba(41, 121, 255, 0.3);
    z-index: 1000;
}
</style>