Commit 6c32142688766a4a25253b3d1e07a6530bb2907d
1 parent
051dc19f
Refactor build script and enhance sales order handling
- Updated the build script in package.json to remove unnecessary NODE_OPTIONS. - Modified index.vue and Form.vue to manage the visibility of inventory fields based on the source of the order. - Added logic to ensure sales orders from the backend are marked correctly and can be edited based on their status. - Introduced new methods to handle order source and approval logic in the sales order forms. - Updated the API service to reflect changes in order status and source handling for sales orders.
Showing
11 changed files
with
1215 additions
and
35 deletions
Antis.Erp.Plat/antis-ncc-admin/package.json
| @@ -7,7 +7,7 @@ | @@ -7,7 +7,7 @@ | ||
| 7 | "scripts": { | 7 | "scripts": { |
| 8 | "dev": "vue-cli-service serve --open", | 8 | "dev": "vue-cli-service serve --open", |
| 9 | "dev:3000": "vue-cli-service serve --port 3000", | 9 | "dev:3000": "vue-cli-service serve --port 3000", |
| 10 | - "build": "cross-env NODE_ENV=production NODE_OPTIONS=--openssl-legacy-provider vue-cli-service build", | 10 | + "build": "cross-env NODE_ENV=production vue-cli-service build", |
| 11 | "build:staging": "cross-env NODE_ENV=production vue-cli-service build --mode staging", | 11 | "build:staging": "cross-env NODE_ENV=production vue-cli-service build --mode staging", |
| 12 | "build:javaBootDev": "cross-env NODE_ENV=production vue-cli-service build --mode javaBootDev", | 12 | "build:javaBootDev": "cross-env NODE_ENV=production vue-cli-service build --mode javaBootDev", |
| 13 | "build:javaBootTest": "cross-env NODE_ENV=production vue-cli-service build --mode javaBootTest", | 13 | "build:javaBootTest": "cross-env NODE_ENV=production vue-cli-service build --mode javaBootTest", |
Antis.Erp.Plat/antis-ncc-admin/src/views/wtSp/index.vue
| @@ -45,7 +45,7 @@ | @@ -45,7 +45,7 @@ | ||
| 45 | <num-range v-model="query.zg"></num-range> | 45 | <num-range v-model="query.zg"></num-range> |
| 46 | </el-form-item> | 46 | </el-form-item> |
| 47 | </el-col> | 47 | </el-col> |
| 48 | - <el-col :span="6"> | 48 | + <el-col :span="6" v-if="false"> |
| 49 | <el-form-item label="库存"> | 49 | <el-form-item label="库存"> |
| 50 | <num-range v-model="query.kc"></num-range> | 50 | <num-range v-model="query.kc"></num-range> |
| 51 | </el-form-item> | 51 | </el-form-item> |
| @@ -113,7 +113,7 @@ | @@ -113,7 +113,7 @@ | ||
| 113 | </el-table-column> | 113 | </el-table-column> |
| 114 | <el-table-column prop="lsj" label="零售价" align="left" /> | 114 | <el-table-column prop="lsj" label="零售价" align="left" /> |
| 115 | <el-table-column prop="zg" label="限购" align="left" /> | 115 | <el-table-column prop="zg" label="限购" align="left" /> |
| 116 | - <el-table-column prop="kc" label="库存" align="left" /> | 116 | + <el-table-column prop="kc" label="库存" align="left" v-if="false" /> |
| 117 | <el-table-column prop="shgz" label="售后规则" align="left" /> | 117 | <el-table-column prop="shgz" label="售后规则" align="left" /> |
| 118 | <el-table-column prop="yfgz" label="运费规则" align="left" /> | 118 | <el-table-column prop="yfgz" label="运费规则" align="left" /> |
| 119 | <el-table-column label="销售渠道" prop="xsqd" align="left"> | 119 | <el-table-column label="销售渠道" prop="xsqd" align="left"> |
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsckd/Form.vue
| @@ -329,6 +329,7 @@ | @@ -329,6 +329,7 @@ | ||
| 329 | djlx:undefined, | 329 | djlx:undefined, |
| 330 | djzt: '', // 单据状态 | 330 | djzt: '', // 单据状态 |
| 331 | cbje: undefined, // 主表出库成本合计(详情/已保存单据由后端返回) | 331 | cbje: undefined, // 主表出库成本合计(详情/已保存单据由后端返回) |
| 332 | + ly: '后台', // 单据来源:后台录入为「后台」;收银台为「门店」,后台不可改 | ||
| 332 | }, | 333 | }, |
| 333 | rules: { | 334 | rules: { |
| 334 | }, | 335 | }, |
| @@ -393,6 +394,12 @@ | @@ -393,6 +394,12 @@ | ||
| 393 | mounted() { | 394 | mounted() { |
| 394 | }, | 395 | }, |
| 395 | methods: { | 396 | methods: { |
| 397 | + /** ERP 新建/保存销售出库单时固定为「后台」,避免与收银台「门店」混淆 */ | ||
| 398 | + ensureBackendSalesSource() { | ||
| 399 | + if (this.dataForm.djlx === '销售出库单') { | ||
| 400 | + this.dataForm.ly = this.dataForm.ly || '后台' | ||
| 401 | + } | ||
| 402 | + }, | ||
| 396 | // 获取商品信息(只通过API获取序列号类型) | 403 | // 获取商品信息(只通过API获取序列号类型) |
| 397 | async getProductInfo(productId) { | 404 | async getProductInfo(productId) { |
| 398 | const key = String(productId); | 405 | const key = String(productId); |
| @@ -720,6 +727,8 @@ | @@ -720,6 +727,8 @@ | ||
| 720 | }) | 727 | }) |
| 721 | } | 728 | } |
| 722 | else{ | 729 | else{ |
| 730 | + _this.dataForm.ly = '后台'; | ||
| 731 | + _this.dataForm.djlx = '销售出库单'; | ||
| 723 | // 新建时加载默认选项设置 | 732 | // 新建时加载默认选项设置 |
| 724 | request({ url: '/api/Extend/WtMrsz', method: 'get' }).then(res => { | 733 | request({ url: '/api/Extend/WtMrsz', method: 'get' }).then(res => { |
| 725 | if (res.data) { | 734 | if (res.data) { |
| @@ -739,6 +748,7 @@ | @@ -739,6 +748,7 @@ | ||
| 739 | async saveDraft() { | 748 | async saveDraft() { |
| 740 | // 确保单据类型字段赋值 | 749 | // 确保单据类型字段赋值 |
| 741 | this.dataForm.djlx = '销售出库单'; | 750 | this.dataForm.djlx = '销售出库单'; |
| 751 | + this.ensureBackendSalesSource(); | ||
| 742 | this.$refs['elForm'].validate(async (valid) => { | 752 | this.$refs['elForm'].validate(async (valid) => { |
| 743 | if (valid) { | 753 | if (valid) { |
| 744 | try { | 754 | try { |
| @@ -807,6 +817,7 @@ | @@ -807,6 +817,7 @@ | ||
| 807 | this.dataForm.djlx = '销售出库单'; | 817 | this.dataForm.djlx = '销售出库单'; |
| 808 | // 确保单据状态为待审核 | 818 | // 确保单据状态为待审核 |
| 809 | this.dataForm.djzt = '待审核'; | 819 | this.dataForm.djzt = '待审核'; |
| 820 | + this.ensureBackendSalesSource(); | ||
| 810 | // 检查是否有明细数据 | 821 | // 检查是否有明细数据 |
| 811 | if (!this.dataForm.wtXsckdMxList || this.dataForm.wtXsckdMxList.length === 0) { | 822 | if (!this.dataForm.wtXsckdMxList || this.dataForm.wtXsckdMxList.length === 0) { |
| 812 | console.log('没有明细数据,跳过序列号验证'); | 823 | console.log('没有明细数据,跳过序列号验证'); |
| @@ -916,6 +927,7 @@ | @@ -916,6 +927,7 @@ | ||
| 916 | if (valid) { | 927 | if (valid) { |
| 917 | console.log('表单验证通过,继续提交...'); | 928 | console.log('表单验证通过,继续提交...'); |
| 918 | try { | 929 | try { |
| 930 | + this.ensureBackendSalesSource(); | ||
| 919 | // 格式化所有明细行的金额字段为 2 位小数 | 931 | // 格式化所有明细行的金额字段为 2 位小数 |
| 920 | this.dataForm.wtXsckdMxList.forEach(row => { | 932 | this.dataForm.wtXsckdMxList.forEach(row => { |
| 921 | if (row.dj) { | 933 | if (row.dj) { |
| @@ -996,6 +1008,7 @@ | @@ -996,6 +1008,7 @@ | ||
| 996 | if (valid) { | 1008 | if (valid) { |
| 997 | console.log('表单验证通过,继续提交...'); | 1009 | console.log('表单验证通过,继续提交...'); |
| 998 | try { | 1010 | try { |
| 1011 | + this.ensureBackendSalesSource(); | ||
| 999 | if (!this.dataForm.id) { | 1012 | if (!this.dataForm.id) { |
| 1000 | const res = await request({ | 1013 | const res = await request({ |
| 1001 | url: `/api/Extend/WtXsckd`, | 1014 | url: `/api/Extend/WtXsckd`, |
| @@ -1574,13 +1587,13 @@ | @@ -1574,13 +1587,13 @@ | ||
| 1574 | }, | 1587 | }, |
| 1575 | getSpOptionLabel(item) { | 1588 | getSpOptionLabel(item) { |
| 1576 | const base = ((item.spbm || '') + ' ' + (item.F_Spmc || '')).trim() | 1589 | const base = ((item.spbm || '') + ' ' + (item.F_Spmc || '')).trim() |
| 1577 | - const c = this.productCostPreviewMap[item.F_Id] | ||
| 1578 | - if (c != null && c !== '' && !isNaN(parseFloat(c))) { | ||
| 1579 | - return base + ' (成本¥' + parseFloat(c).toFixed(2) + ')' | ||
| 1580 | - } | ||
| 1581 | - if (!this.costContextCk()) { | ||
| 1582 | - return base + ' (选仓库后显示成本)' | ||
| 1583 | - } | 1590 | + // const c = this.productCostPreviewMap[item.F_Id] |
| 1591 | + // if (c != null && c !== '' && !isNaN(parseFloat(c))) { | ||
| 1592 | + // return base + ' (成本¥' + parseFloat(c).toFixed(2) + ')' | ||
| 1593 | + // } | ||
| 1594 | + // if (!this.costContextCk()) { | ||
| 1595 | + // return base + ' (选仓库后显示成本)' | ||
| 1596 | + // } | ||
| 1584 | return base | 1597 | return base |
| 1585 | }, | 1598 | }, |
| 1586 | async loadProductCostPreviewMap() { | 1599 | async loadProductCostPreviewMap() { |
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsckd/detail-view.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-dialog | ||
| 3 | + title="销售出库单详情" | ||
| 4 | + :close-on-click-modal="false" | ||
| 5 | + :visible.sync="visible" | ||
| 6 | + class="NCC-dialog NCC-dialog_center xsckd-detail-dialog" | ||
| 7 | + lock-scroll | ||
| 8 | + width="1200px" | ||
| 9 | + top="6vh" | ||
| 10 | + @close="handleClose" | ||
| 11 | + > | ||
| 12 | + <div v-loading="loading" class="xsckd-detail-wrap"> | ||
| 13 | + <template v-if="detail"> | ||
| 14 | + <div class="detail-top"> | ||
| 15 | + <div class="detail-top__id"> | ||
| 16 | + <i class="el-icon-document detail-top__icon detail-top__icon--primary" /> | ||
| 17 | + <span class="cell-nowrap">{{ cellText(detail.id) }}</span> | ||
| 18 | + </div> | ||
| 19 | + <el-tag :type="djztTagType" size="medium" effect="plain">{{ djztLabel }}</el-tag> | ||
| 20 | + </div> | ||
| 21 | + | ||
| 22 | + <div class="collect-stat-card"> | ||
| 23 | + <div class="collect-stat-card__inner"> | ||
| 24 | + <i class="el-icon-coin collect-stat-card__coin" /> | ||
| 25 | + <div class="collect-stat-card__text"> | ||
| 26 | + <div class="collect-stat-card__label">收款金额(与列表一致)</div> | ||
| 27 | + <div class="collect-stat-card__value cell-nowrap">{{ displayCollectionAmount }}</div> | ||
| 28 | + </div> | ||
| 29 | + </div> | ||
| 30 | + <p class="collect-stat-card__hint"> | ||
| 31 | + <i class="el-icon-info" /> | ||
| 32 | + 有原价时收款=原价−优惠;组合支付以 skmx 汇总为准 | ||
| 33 | + </p> | ||
| 34 | + </div> | ||
| 35 | + | ||
| 36 | + <el-descriptions | ||
| 37 | + title="基本信息" | ||
| 38 | + :column="2" | ||
| 39 | + border | ||
| 40 | + size="small" | ||
| 41 | + class="detail-descriptions" | ||
| 42 | + :label-style="{ width: '108px' }" | ||
| 43 | + > | ||
| 44 | + <el-descriptions-item label="单据日期"> | ||
| 45 | + <span class="cell-nowrap"> | ||
| 46 | + <i class="el-icon-date desc-icon desc-icon--primary" /> | ||
| 47 | + {{ formatDjrq(detail.djrq) }} | ||
| 48 | + </span> | ||
| 49 | + </el-descriptions-item> | ||
| 50 | + <el-descriptions-item label="单据类型"> | ||
| 51 | + <span class="cell-nowrap"> | ||
| 52 | + <i class="el-icon-tickets desc-icon desc-icon--info" /> | ||
| 53 | + {{ cellText(detail.djlx || '销售出库单') }} | ||
| 54 | + </span> | ||
| 55 | + </el-descriptions-item> | ||
| 56 | + <el-descriptions-item label="单据来源"> | ||
| 57 | + <span class="cell-nowrap"> | ||
| 58 | + <i class="el-icon-s-promotion desc-icon desc-icon--muted" /> | ||
| 59 | + {{ formatLy(detail.ly) }} | ||
| 60 | + </span> | ||
| 61 | + </el-descriptions-item> | ||
| 62 | + <el-descriptions-item label="出库仓库"> | ||
| 63 | + <span class="cell-nowrap"> | ||
| 64 | + <i class="el-icon-s-home desc-icon desc-icon--muted" /> | ||
| 65 | + {{ labelFromOptions(detail.cjckId || detail.cjck, cjckOptions) }} | ||
| 66 | + </span> | ||
| 67 | + </el-descriptions-item> | ||
| 68 | + <el-descriptions-item label="经手人"> | ||
| 69 | + <span class="cell-nowrap"> | ||
| 70 | + <i class="el-icon-user desc-icon desc-icon--primary" /> | ||
| 71 | + {{ cellText(detail.jsr) }} | ||
| 72 | + </span> | ||
| 73 | + </el-descriptions-item> | ||
| 74 | + <el-descriptions-item label="会员手机"> | ||
| 75 | + <span class="cell-nowrap"> | ||
| 76 | + <i class="el-icon-phone desc-icon desc-icon--info" /> | ||
| 77 | + {{ cellText(detail.hysjh) }} | ||
| 78 | + </span> | ||
| 79 | + </el-descriptions-item> | ||
| 80 | + </el-descriptions> | ||
| 81 | + | ||
| 82 | + <div class="detail-section-head"> | ||
| 83 | + <i class="el-icon-s-order detail-section-head__icon" /> | ||
| 84 | + <span>出库明细</span> | ||
| 85 | + <span class="detail-section-head__sub">(列表不换行展示)</span> | ||
| 86 | + </div> | ||
| 87 | + <el-table | ||
| 88 | + :data="detail.wtXsckdMxList || []" | ||
| 89 | + size="small" | ||
| 90 | + border | ||
| 91 | + stripe | ||
| 92 | + show-summary | ||
| 93 | + :summary-method="getSummaries" | ||
| 94 | + class="detail-mx-table" | ||
| 95 | + :empty-text="'无明细'" | ||
| 96 | + > | ||
| 97 | + <el-table-column type="index" width="52" label="#" align="center" /> | ||
| 98 | + <el-table-column label="出库仓库" min-width="118" show-overflow-tooltip> | ||
| 99 | + <template slot-scope="scope"> | ||
| 100 | + <span class="cell-nowrap mx-cell"> | ||
| 101 | + <i class="el-icon-location-outline mx-cell__icon mx-cell__icon--muted" /> | ||
| 102 | + {{ labelFromOptions(scope.row.ckck, cjckOptions) }} | ||
| 103 | + </span> | ||
| 104 | + </template> | ||
| 105 | + </el-table-column> | ||
| 106 | + <el-table-column label="商品" min-width="160" show-overflow-tooltip> | ||
| 107 | + <template slot-scope="scope"> | ||
| 108 | + <span class="cell-nowrap mx-cell"> | ||
| 109 | + <i class="el-icon-goods mx-cell__icon mx-cell__icon--primary" /> | ||
| 110 | + {{ cellText(scope.row.spmc) }} | ||
| 111 | + </span> | ||
| 112 | + </template> | ||
| 113 | + </el-table-column> | ||
| 114 | + <el-table-column prop="sl" label="数量" width="72" align="right"> | ||
| 115 | + <template slot-scope="scope"> | ||
| 116 | + <span class="cell-nowrap">{{ cellText(scope.row.sl) }}</span> | ||
| 117 | + </template> | ||
| 118 | + </el-table-column> | ||
| 119 | + <el-table-column prop="dj" label="单价" width="96" align="right"> | ||
| 120 | + <template slot-scope="scope"> | ||
| 121 | + <span class="cell-nowrap">{{ formatMoneyCol(scope.row.dj) }}</span> | ||
| 122 | + </template> | ||
| 123 | + </el-table-column> | ||
| 124 | + <el-table-column prop="je" label="金额" width="96" align="right"> | ||
| 125 | + <template slot-scope="scope"> | ||
| 126 | + <span class="cell-nowrap mx-cell__money">{{ formatMoneyCol(scope.row.je) }}</span> | ||
| 127 | + </template> | ||
| 128 | + </el-table-column> | ||
| 129 | + <el-table-column prop="cbje" label="成本" width="96" align="right"> | ||
| 130 | + <template slot-scope="scope"> | ||
| 131 | + <span class="cell-nowrap">{{ formatMoneyCol(scope.row.cbje) }}</span> | ||
| 132 | + </template> | ||
| 133 | + </el-table-column> | ||
| 134 | + <el-table-column label="序列号" min-width="168"> | ||
| 135 | + <template slot-scope="scope"> | ||
| 136 | + <div v-if="scope.row.selectedSerialNumbers && scope.row.selectedSerialNumbers.length" class="sn-tags"> | ||
| 137 | + <el-tag | ||
| 138 | + v-for="(sn, idx) in scope.row.selectedSerialNumbers" | ||
| 139 | + :key="idx" | ||
| 140 | + size="mini" | ||
| 141 | + type="warning" | ||
| 142 | + class="sn-tag" | ||
| 143 | + >{{ sn }}</el-tag> | ||
| 144 | + </div> | ||
| 145 | + <span v-else class="text-muted">无</span> | ||
| 146 | + </template> | ||
| 147 | + </el-table-column> | ||
| 148 | + </el-table> | ||
| 149 | + | ||
| 150 | + <el-descriptions | ||
| 151 | + title="收款与审核" | ||
| 152 | + :column="2" | ||
| 153 | + border | ||
| 154 | + size="small" | ||
| 155 | + class="detail-descriptions detail-descriptions--footer" | ||
| 156 | + :label-style="{ width: '108px' }" | ||
| 157 | + > | ||
| 158 | + <el-descriptions-item label="收款账户"> | ||
| 159 | + <span class="cell-nowrap"> | ||
| 160 | + <i class="el-icon-bank-card desc-icon desc-icon--success" /> | ||
| 161 | + {{ labelFromOptions(detail.skzh, skzhOptions) }} | ||
| 162 | + </span> | ||
| 163 | + </el-descriptions-item> | ||
| 164 | + <el-descriptions-item label="原价"> | ||
| 165 | + <span class="cell-nowrap"> | ||
| 166 | + <i class="el-icon-money desc-icon desc-icon--primary" /> | ||
| 167 | + {{ displayOriginalPrice }} | ||
| 168 | + </span> | ||
| 169 | + </el-descriptions-item> | ||
| 170 | + <el-descriptions-item label="优惠金额"> | ||
| 171 | + <span class="cell-nowrap"> | ||
| 172 | + <i class="el-icon-bottom desc-icon desc-icon--warning" /> | ||
| 173 | + {{ displayDiscountAmount }} | ||
| 174 | + </span> | ||
| 175 | + </el-descriptions-item> | ||
| 176 | + <el-descriptions-item label="出库成本"> | ||
| 177 | + <span class="cell-nowrap"> | ||
| 178 | + <i class="el-icon-s-grid desc-icon desc-icon--info" /> | ||
| 179 | + {{ formatMoneyCol(detail.cbje) }} | ||
| 180 | + </span> | ||
| 181 | + </el-descriptions-item> | ||
| 182 | + <el-descriptions-item label="制单人"> | ||
| 183 | + <span class="cell-nowrap"> | ||
| 184 | + <i class="el-icon-edit-outline desc-icon desc-icon--muted" /> | ||
| 185 | + {{ cellText(detail.zdr) }} | ||
| 186 | + </span> | ||
| 187 | + </el-descriptions-item> | ||
| 188 | + <el-descriptions-item label="审核人"> | ||
| 189 | + <span class="cell-nowrap"> | ||
| 190 | + <i class="el-icon-s-check desc-icon desc-icon--warning" /> | ||
| 191 | + {{ cellText(detail.shr) }} | ||
| 192 | + </span> | ||
| 193 | + </el-descriptions-item> | ||
| 194 | + <el-descriptions-item label="过账人"> | ||
| 195 | + <span class="cell-nowrap"> | ||
| 196 | + <i class="el-icon-s-promotion desc-icon desc-icon--info" /> | ||
| 197 | + {{ cellText(detail.gzr) }} | ||
| 198 | + </span> | ||
| 199 | + </el-descriptions-item> | ||
| 200 | + <el-descriptions-item label="备注" :span="2"> | ||
| 201 | + <span class="detail-bz">{{ cellText(detail.bz) }}</span> | ||
| 202 | + </el-descriptions-item> | ||
| 203 | + </el-descriptions> | ||
| 204 | + </template> | ||
| 205 | + <div v-else-if="!loading" class="detail-empty"> | ||
| 206 | + <i class="el-icon-warning-outline" /> | ||
| 207 | + <span>暂无数据</span> | ||
| 208 | + </div> | ||
| 209 | + </div> | ||
| 210 | + </el-dialog> | ||
| 211 | +</template> | ||
| 212 | + | ||
| 213 | +<script> | ||
| 214 | +import request from '@/utils/request' | ||
| 215 | +import { getDictionaryDataSelector } from '@/api/systemData/dictionary' | ||
| 216 | +import { previewDataInterface } from '@/api/systemData/dataInterface' | ||
| 217 | +import { dynamicText } from '@/filters' | ||
| 218 | + | ||
| 219 | +export default { | ||
| 220 | + name: 'WtXsckdDetailView', | ||
| 221 | + data() { | ||
| 222 | + return { | ||
| 223 | + visible: false, | ||
| 224 | + loading: false, | ||
| 225 | + detail: null, | ||
| 226 | + cjckOptions: [], | ||
| 227 | + skzhOptions: [] | ||
| 228 | + } | ||
| 229 | + }, | ||
| 230 | + computed: { | ||
| 231 | + djztLabel() { | ||
| 232 | + const z = this.detail && this.detail.djzt | ||
| 233 | + if (!z) return '待审核' | ||
| 234 | + return z | ||
| 235 | + }, | ||
| 236 | + djztTagType() { | ||
| 237 | + const z = this.detail && this.detail.djzt | ||
| 238 | + if (z === '已审核') return 'success' | ||
| 239 | + if (z === '一级已审') return '' | ||
| 240 | + if (z === '草稿') return 'info' | ||
| 241 | + if (z === '待审核' || !z) return 'warning' | ||
| 242 | + return 'info' | ||
| 243 | + }, | ||
| 244 | + displayOriginalPrice() { | ||
| 245 | + const row = this.detail | ||
| 246 | + if (!row) return '0.00' | ||
| 247 | + const ydje = row.ydje != null && row.ydje !== '' | ||
| 248 | + const val = ydje | ||
| 249 | + ? parseFloat(row.ydje) | ||
| 250 | + : (parseFloat(this.displayCollectionRaw) || 0) + (parseFloat(row.ysje) || 0) | ||
| 251 | + return (typeof val === 'number' && !isNaN(val)) ? val.toFixed(2) : '0.00' | ||
| 252 | + }, | ||
| 253 | + displayDiscountAmount() { | ||
| 254 | + const row = this.detail | ||
| 255 | + if (!row) return '0.00' | ||
| 256 | + const ysje = parseFloat(row.ysje) || 0 | ||
| 257 | + return ysje.toFixed(2) | ||
| 258 | + }, | ||
| 259 | + displayCollectionRaw() { | ||
| 260 | + const row = this.detail | ||
| 261 | + if (!row) return 0 | ||
| 262 | + const hasYdje = row.ydje != null && row.ydje !== '' | ||
| 263 | + if (hasYdje) { | ||
| 264 | + const ydje = parseFloat(row.ydje) | ||
| 265 | + const ysje = parseFloat(row.ysje) || 0 | ||
| 266 | + return !isNaN(ydje) ? ydje - ysje : 0 | ||
| 267 | + } | ||
| 268 | + if (row.skmx) { | ||
| 269 | + try { | ||
| 270 | + const paymentDetails = JSON.parse(row.skmx) | ||
| 271 | + if (Array.isArray(paymentDetails) && paymentDetails.length > 0) { | ||
| 272 | + return paymentDetails.reduce((sum, item) => sum + (parseFloat(item.skje) || 0), 0) | ||
| 273 | + } | ||
| 274 | + } catch (e) { | ||
| 275 | + // ignore | ||
| 276 | + } | ||
| 277 | + } | ||
| 278 | + if (row.skje != null && row.skje !== '') return parseFloat(row.skje) | ||
| 279 | + return 0 | ||
| 280 | + }, | ||
| 281 | + displayCollectionAmount() { | ||
| 282 | + const n = this.displayCollectionRaw | ||
| 283 | + if (typeof n === 'number' && !isNaN(n)) return n.toFixed(2) | ||
| 284 | + return '0.00' | ||
| 285 | + } | ||
| 286 | + }, | ||
| 287 | + methods: { | ||
| 288 | + labelFromOptions(value, options) { | ||
| 289 | + if (value === null || value === undefined || value === '') return '无' | ||
| 290 | + const opts = options || [] | ||
| 291 | + let text = dynamicText(value, opts) | ||
| 292 | + if (text && text !== value) return text | ||
| 293 | + const row = opts.find( | ||
| 294 | + o => o.F_Id === value || String(o.F_Id) === String(value) || o.id === value || String(o.id) === String(value) | ||
| 295 | + ) | ||
| 296 | + if (row) return row.F_mdmc || row.fullName || value | ||
| 297 | + return text || String(value) | ||
| 298 | + }, | ||
| 299 | + cellText(v) { | ||
| 300 | + if (v === null || v === undefined || v === '') return '无' | ||
| 301 | + return v | ||
| 302 | + }, | ||
| 303 | + formatMoneyCol(v) { | ||
| 304 | + if (v === null || v === undefined || v === '') return '无' | ||
| 305 | + const n = Number(v) | ||
| 306 | + return isNaN(n) ? '无' : n.toFixed(2) | ||
| 307 | + }, | ||
| 308 | + formatLy(ly) { | ||
| 309 | + if (ly == null || ly === '') return '无' | ||
| 310 | + if (ly === '门店') return '门店(收银台)' | ||
| 311 | + if (ly === '抖音订单') return '抖音订单' | ||
| 312 | + return ly | ||
| 313 | + }, | ||
| 314 | + formatDjrq(ts) { | ||
| 315 | + if (ts == null || ts === '') return '无' | ||
| 316 | + const d = new Date(typeof ts === 'number' ? ts : Number(ts)) | ||
| 317 | + if (isNaN(d.getTime())) return '无' | ||
| 318 | + const y = d.getFullYear() | ||
| 319 | + const m = String(d.getMonth() + 1).padStart(2, '0') | ||
| 320 | + const day = String(d.getDate()).padStart(2, '0') | ||
| 321 | + return `${y}-${m}-${day}` | ||
| 322 | + }, | ||
| 323 | + getSummaries(param) { | ||
| 324 | + const { columns, data } = param | ||
| 325 | + const sums = [] | ||
| 326 | + columns.forEach((column, index) => { | ||
| 327 | + if (index === 0) { | ||
| 328 | + sums[index] = '合计' | ||
| 329 | + return | ||
| 330 | + } | ||
| 331 | + if (column.property === 'sl') { | ||
| 332 | + sums[index] = data.reduce((t, row) => t + (parseFloat(row.sl) || 0), 0) | ||
| 333 | + } else if (column.property === 'je') { | ||
| 334 | + sums[index] = data | ||
| 335 | + .reduce((t, row) => t + (parseFloat(row.je) || 0), 0) | ||
| 336 | + .toFixed(2) | ||
| 337 | + } else if (column.property === 'cbje') { | ||
| 338 | + sums[index] = data | ||
| 339 | + .reduce((t, row) => t + (parseFloat(row.cbje) || 0), 0) | ||
| 340 | + .toFixed(2) | ||
| 341 | + } else { | ||
| 342 | + sums[index] = '' | ||
| 343 | + } | ||
| 344 | + }) | ||
| 345 | + return sums | ||
| 346 | + }, | ||
| 347 | + handleClose() { | ||
| 348 | + this.detail = null | ||
| 349 | + this.$emit('close') | ||
| 350 | + }, | ||
| 351 | + init(id) { | ||
| 352 | + if (!id) return | ||
| 353 | + this.visible = true | ||
| 354 | + this.loading = true | ||
| 355 | + this.detail = null | ||
| 356 | + request({ | ||
| 357 | + url: '/api/Extend/WtXsckd/' + id, | ||
| 358 | + method: 'get' | ||
| 359 | + }) | ||
| 360 | + .then(res => { | ||
| 361 | + this.detail = res.data || null | ||
| 362 | + if (this.detail && !this.detail.wtXsckdMxList) { | ||
| 363 | + this.$set(this.detail, 'wtXsckdMxList', []) | ||
| 364 | + } | ||
| 365 | + }) | ||
| 366 | + .catch(() => { | ||
| 367 | + this.$message.error('加载详情失败') | ||
| 368 | + this.visible = false | ||
| 369 | + }) | ||
| 370 | + .finally(() => { | ||
| 371 | + this.loading = false | ||
| 372 | + }) | ||
| 373 | + }, | ||
| 374 | + loadOptions() { | ||
| 375 | + previewDataInterface('681758216954053893').then(res => { | ||
| 376 | + this.cjckOptions = res.data || [] | ||
| 377 | + }) | ||
| 378 | + getDictionaryDataSelector('681761709836207365').then(res => { | ||
| 379 | + this.skzhOptions = res.data.list || [] | ||
| 380 | + }) | ||
| 381 | + } | ||
| 382 | + }, | ||
| 383 | + created() { | ||
| 384 | + this.loadOptions() | ||
| 385 | + } | ||
| 386 | +} | ||
| 387 | +</script> | ||
| 388 | + | ||
| 389 | +<style scoped lang="scss"> | ||
| 390 | +.cell-nowrap { | ||
| 391 | + white-space: nowrap; | ||
| 392 | +} | ||
| 393 | +.text-muted { | ||
| 394 | + color: #909399; | ||
| 395 | + font-size: 12px; | ||
| 396 | +} | ||
| 397 | + | ||
| 398 | +.xsckd-detail-wrap { | ||
| 399 | + min-height: 160px; | ||
| 400 | + margin-bottom: 30px; | ||
| 401 | +} | ||
| 402 | + | ||
| 403 | +.detail-top { | ||
| 404 | + display: flex; | ||
| 405 | + align-items: center; | ||
| 406 | + justify-content: space-between; | ||
| 407 | + flex-wrap: wrap; | ||
| 408 | + gap: 10px; | ||
| 409 | + margin-bottom: 14px; | ||
| 410 | + padding-bottom: 12px; | ||
| 411 | + border-bottom: 1px solid #ebeef5; | ||
| 412 | +} | ||
| 413 | +.detail-top__id { | ||
| 414 | + display: flex; | ||
| 415 | + align-items: center; | ||
| 416 | + gap: 8px; | ||
| 417 | + font-size: 15px; | ||
| 418 | + font-weight: 600; | ||
| 419 | + color: #303133; | ||
| 420 | +} | ||
| 421 | +.detail-top__icon { | ||
| 422 | + font-size: 18px; | ||
| 423 | +} | ||
| 424 | +.detail-top__icon--primary { | ||
| 425 | + color: #409eff; | ||
| 426 | +} | ||
| 427 | + | ||
| 428 | +.collect-stat-card { | ||
| 429 | + height: 100px; | ||
| 430 | + padding: 12px; | ||
| 431 | + border-radius: 12px; | ||
| 432 | + background: linear-gradient(135deg, #ecf5ff 0%, #f5f9ff 100%); | ||
| 433 | + border: 1px solid #d9ecff; | ||
| 434 | + margin-bottom: 16px; | ||
| 435 | + box-sizing: border-box; | ||
| 436 | + display: flex; | ||
| 437 | + flex-direction: column; | ||
| 438 | + justify-content: center; | ||
| 439 | +} | ||
| 440 | +.collect-stat-card__inner { | ||
| 441 | + display: flex; | ||
| 442 | + align-items: center; | ||
| 443 | + gap: 14px; | ||
| 444 | +} | ||
| 445 | +.collect-stat-card__coin { | ||
| 446 | + font-size: 36px; | ||
| 447 | + color: #409eff; | ||
| 448 | + line-height: 1; | ||
| 449 | +} | ||
| 450 | +.collect-stat-card__label { | ||
| 451 | + font-size: 12px; | ||
| 452 | + color: #909399; | ||
| 453 | + margin-bottom: 4px; | ||
| 454 | +} | ||
| 455 | +.collect-stat-card__value { | ||
| 456 | + font-size: 22px; | ||
| 457 | + font-weight: 600; | ||
| 458 | + color: #303133; | ||
| 459 | + letter-spacing: 0.02em; | ||
| 460 | +} | ||
| 461 | +.collect-stat-card__hint { | ||
| 462 | + margin: 10px 0 0; | ||
| 463 | + font-size: 12px; | ||
| 464 | + color: #909399; | ||
| 465 | + line-height: 1.4; | ||
| 466 | + display: flex; | ||
| 467 | + align-items: flex-start; | ||
| 468 | + gap: 4px; | ||
| 469 | +} | ||
| 470 | +.collect-stat-card__hint .el-icon-info { | ||
| 471 | + margin-top: 2px; | ||
| 472 | + color: #c0c4cc; | ||
| 473 | +} | ||
| 474 | + | ||
| 475 | +.detail-descriptions { | ||
| 476 | + margin-bottom: 8px; | ||
| 477 | +} | ||
| 478 | +.detail-descriptions--footer { | ||
| 479 | + margin-top: 14px; | ||
| 480 | +} | ||
| 481 | +.desc-icon { | ||
| 482 | + margin-right: 6px; | ||
| 483 | + font-size: 14px; | ||
| 484 | + vertical-align: -1px; | ||
| 485 | +} | ||
| 486 | +.desc-icon--primary { | ||
| 487 | + color: #409eff; | ||
| 488 | +} | ||
| 489 | +.desc-icon--success { | ||
| 490 | + color: #67c23a; | ||
| 491 | +} | ||
| 492 | +.desc-icon--warning { | ||
| 493 | + color: #e6a23c; | ||
| 494 | +} | ||
| 495 | +.desc-icon--info { | ||
| 496 | + color: #909399; | ||
| 497 | +} | ||
| 498 | +.desc-icon--muted { | ||
| 499 | + color: #c0c4cc; | ||
| 500 | +} | ||
| 501 | + | ||
| 502 | +.detail-section-head { | ||
| 503 | + display: flex; | ||
| 504 | + align-items: center; | ||
| 505 | + gap: 6px; | ||
| 506 | + margin: 16px 0 10px; | ||
| 507 | + font-size: 14px; | ||
| 508 | + font-weight: 600; | ||
| 509 | + color: #303133; | ||
| 510 | +} | ||
| 511 | +.detail-section-head__icon { | ||
| 512 | + color: #409eff; | ||
| 513 | + font-size: 16px; | ||
| 514 | +} | ||
| 515 | +.detail-section-head__sub { | ||
| 516 | + font-size: 12px; | ||
| 517 | + font-weight: normal; | ||
| 518 | + color: #909399; | ||
| 519 | +} | ||
| 520 | + | ||
| 521 | +.detail-mx-table { | ||
| 522 | + width: 100%; | ||
| 523 | +} | ||
| 524 | +.mx-cell { | ||
| 525 | + display: inline-flex; | ||
| 526 | + align-items: center; | ||
| 527 | + max-width: 100%; | ||
| 528 | +} | ||
| 529 | +.mx-cell__icon { | ||
| 530 | + margin-right: 4px; | ||
| 531 | + flex-shrink: 0; | ||
| 532 | + font-size: 14px; | ||
| 533 | +} | ||
| 534 | +.mx-cell__icon--primary { | ||
| 535 | + color: #409eff; | ||
| 536 | +} | ||
| 537 | +.mx-cell__icon--muted { | ||
| 538 | + color: #909399; | ||
| 539 | +} | ||
| 540 | +.mx-cell__money { | ||
| 541 | + color: #303133; | ||
| 542 | + font-weight: 500; | ||
| 543 | +} | ||
| 544 | + | ||
| 545 | +.sn-tags { | ||
| 546 | + display: flex; | ||
| 547 | + flex-wrap: wrap; | ||
| 548 | + gap: 4px; | ||
| 549 | + align-items: center; | ||
| 550 | +} | ||
| 551 | +.sn-tag { | ||
| 552 | + margin: 0 !important; | ||
| 553 | +} | ||
| 554 | + | ||
| 555 | +.detail-bz { | ||
| 556 | + white-space: pre-wrap; | ||
| 557 | + word-break: break-all; | ||
| 558 | + line-height: 1.5; | ||
| 559 | + color: #606266; | ||
| 560 | +} | ||
| 561 | + | ||
| 562 | +.detail-empty { | ||
| 563 | + display: flex; | ||
| 564 | + align-items: center; | ||
| 565 | + justify-content: center; | ||
| 566 | + gap: 8px; | ||
| 567 | + padding: 40px; | ||
| 568 | + color: #909399; | ||
| 569 | + font-size: 14px; | ||
| 570 | +} | ||
| 571 | +.detail-empty .el-icon-warning-outline { | ||
| 572 | + font-size: 20px; | ||
| 573 | + color: #e6a23c; | ||
| 574 | +} | ||
| 575 | + | ||
| 576 | +.xsckd-detail-footer { | ||
| 577 | + text-align: left; | ||
| 578 | +} | ||
| 579 | +</style> |
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsckd/index.vue
| @@ -78,8 +78,9 @@ | @@ -78,8 +78,9 @@ | ||
| 78 | <el-col :span="6"> | 78 | <el-col :span="6"> |
| 79 | <el-form-item label="单据来源"> | 79 | <el-form-item label="单据来源"> |
| 80 | <el-select v-model="query.ly" placeholder="单据来源" clearable > | 80 | <el-select v-model="query.ly" placeholder="单据来源" clearable > |
| 81 | - <el-option label="门店" value="门店"></el-option> | ||
| 82 | - <el-option label="抖音抓单" value="抖音抓单"></el-option> | 81 | + <el-option label="后台" value="后台" /> |
| 82 | + <el-option label="门店(收银台)" value="门店" /> | ||
| 83 | + <el-option label="抖音抓单" value="抖音抓单" /> | ||
| 83 | </el-select> | 84 | </el-select> |
| 84 | </el-form-item> | 85 | </el-form-item> |
| 85 | </el-col> | 86 | </el-col> |
| @@ -138,20 +139,25 @@ | @@ -138,20 +139,25 @@ | ||
| 138 | <el-table-column prop="gzr" label="过账人" align="left" /> | 139 | <el-table-column prop="gzr" label="过账人" align="left" /> |
| 139 | <el-table-column prop="bz" label="备注" align="left" /> | 140 | <el-table-column prop="bz" label="备注" align="left" /> |
| 140 | <el-table-column prop="djlx" label="单据类型" align="left" /> | 141 | <el-table-column prop="djlx" label="单据类型" align="left" /> |
| 142 | + <el-table-column label="单据来源" prop="ly" align="left" min-width="100"> | ||
| 143 | + <template slot-scope="scope">{{ formatLy(scope.row.ly) }}</template> | ||
| 144 | + </el-table-column> | ||
| 141 | <el-table-column prop="djzt" label="审核状态" align="left"> | 145 | <el-table-column prop="djzt" label="审核状态" align="left"> |
| 142 | <template slot-scope="scope"> | 146 | <template slot-scope="scope"> |
| 143 | <el-tag v-if="scope.row.djzt === '已审核'" type="success">已审核</el-tag> | 147 | <el-tag v-if="scope.row.djzt === '已审核'" type="success">已审核</el-tag> |
| 144 | <el-tag v-else-if="scope.row.djzt === '一级已审'" type="">一级已审</el-tag> | 148 | <el-tag v-else-if="scope.row.djzt === '一级已审'" type="">一级已审</el-tag> |
| 149 | + <el-tag v-else-if="scope.row.djzt === '草稿'" type="info">草稿</el-tag> | ||
| 150 | + <el-tag v-else-if="isSkipErpAuditSource(scope.row)" type="success" effect="plain">无需审核</el-tag> | ||
| 145 | <el-tag v-else-if="scope.row.djzt === '待审核'" type="warning">待审核</el-tag> | 151 | <el-tag v-else-if="scope.row.djzt === '待审核'" type="warning">待审核</el-tag> |
| 146 | <el-tag v-else type="warning">{{ scope.row.djzt || '待审核' }}</el-tag> | 152 | <el-tag v-else type="warning">{{ scope.row.djzt || '待审核' }}</el-tag> |
| 147 | </template> | 153 | </template> |
| 148 | </el-table-column> | 154 | </el-table-column> |
| 149 | - <el-table-column label="操作" fixed="right" width="250"> | 155 | + <el-table-column label="操作" fixed="right" width="280"> |
| 150 | <template slot-scope="scope"> | 156 | <template slot-scope="scope"> |
| 151 | - <el-button type="text" @click="addOrUpdateHandle(scope.row.id, true)">查看</el-button> | ||
| 152 | - <el-button type="text" disabled >编辑</el-button> | ||
| 153 | - <el-button type="text" @click="handleApprove(scope.row.id)" v-if="scope.row.djzt === '待审核' || !scope.row.djzt" style="color:#E6A23C">一级审核</el-button> | ||
| 154 | - <el-button type="text" @click="handleApprove(scope.row.id)" v-if="scope.row.djzt === '一级已审'" style="color:#409EFF">二级审核</el-button> | 157 | + <el-button type="text" @click="openDetail(scope.row.id)">查看</el-button> |
| 158 | + <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" v-if="canEditDraft(scope.row)">编辑</el-button> | ||
| 159 | + <el-button type="text" @click="handleApprove(scope.row.id)" v-if="canFirstApprove(scope.row)" style="color:#E6A23C">一级审核</el-button> | ||
| 160 | + <el-button type="text" @click="handleApprove(scope.row.id)" v-if="canSecondApprove(scope.row)" style="color:#409EFF">二级审核</el-button> | ||
| 155 | <el-button type="text" @click="handleDel(scope.row.id)" class="NCC-table-delBtn" >删除</el-button> | 161 | <el-button type="text" @click="handleDel(scope.row.id)" class="NCC-table-delBtn" >删除</el-button> |
| 156 | </template> | 162 | </template> |
| 157 | </el-table-column> | 163 | </el-table-column> |
| @@ -160,6 +166,7 @@ | @@ -160,6 +166,7 @@ | ||
| 160 | </div> | 166 | </div> |
| 161 | </div> | 167 | </div> |
| 162 | <NCC-Form v-if="formVisible" ref="NCCForm" @refresh="refresh" /> | 168 | <NCC-Form v-if="formVisible" ref="NCCForm" @refresh="refresh" /> |
| 169 | + <DetailView v-if="detailVisible" ref="NCCDetailView" @close="detailVisible = false" /> | ||
| 163 | <ExportBox v-if="exportBoxVisible" ref="ExportBox" @download="download" /> | 170 | <ExportBox v-if="exportBoxVisible" ref="ExportBox" @download="download" /> |
| 164 | </div> | 171 | </div> |
| 165 | </template> | 172 | </template> |
| @@ -167,10 +174,11 @@ | @@ -167,10 +174,11 @@ | ||
| 167 | import request from '@/utils/request' | 174 | import request from '@/utils/request' |
| 168 | import { getDictionaryDataSelector } from '@/api/systemData/dictionary' | 175 | import { getDictionaryDataSelector } from '@/api/systemData/dictionary' |
| 169 | import NCCForm from './Form' | 176 | import NCCForm from './Form' |
| 177 | + import DetailView from './detail-view' | ||
| 170 | import ExportBox from './ExportBox' | 178 | import ExportBox from './ExportBox' |
| 171 | import { previewDataInterface } from '@/api/systemData/dataInterface' | 179 | import { previewDataInterface } from '@/api/systemData/dataInterface' |
| 172 | export default { | 180 | export default { |
| 173 | - components: { NCCForm, ExportBox }, | 181 | + components: { NCCForm, DetailView, ExportBox }, |
| 174 | data() { | 182 | data() { |
| 175 | return { | 183 | return { |
| 176 | showAll: false, | 184 | showAll: false, |
| @@ -200,6 +208,7 @@ | @@ -200,6 +208,7 @@ | ||
| 200 | sidx: "", | 208 | sidx: "", |
| 201 | }, | 209 | }, |
| 202 | formVisible: false, | 210 | formVisible: false, |
| 211 | + detailVisible: false, | ||
| 203 | exportBoxVisible: false, | 212 | exportBoxVisible: false, |
| 204 | columnList: [ | 213 | columnList: [ |
| 205 | { prop: 'id', label: '单据编号' }, | 214 | { prop: 'id', label: '单据编号' }, |
| @@ -228,6 +237,33 @@ | @@ -228,6 +237,33 @@ | ||
| 228 | this.getskzhOptions(); | 237 | this.getskzhOptions(); |
| 229 | }, | 238 | }, |
| 230 | methods: { | 239 | methods: { |
| 240 | + /** 收银台/抖音等:不走 ERP 二级审核、仅查看 */ | ||
| 241 | + isSkipErpAuditSource(row) { | ||
| 242 | + if (!row) return false | ||
| 243 | + const ly = row.ly | ||
| 244 | + if (ly === '门店' || ly === '抖音订单' || ly === '抖音抓单') return true | ||
| 245 | + const bz = row.bz != null && row.bz !== '' ? String(row.bz).trim() : '' | ||
| 246 | + if (bz.startsWith('抖音订单:')) return true | ||
| 247 | + return false | ||
| 248 | + }, | ||
| 249 | + /** 后台来源且草稿可编辑 */ | ||
| 250 | + canEditDraft(row) { | ||
| 251 | + return !this.isSkipErpAuditSource(row) && row.djzt === '草稿' | ||
| 252 | + }, | ||
| 253 | + canFirstApprove(row) { | ||
| 254 | + if (this.isSkipErpAuditSource(row)) return false | ||
| 255 | + if (row.djzt === '草稿' || row.djzt === '已审核') return false | ||
| 256 | + return row.djzt === '待审核' || row.djzt === '' || row.djzt == null | ||
| 257 | + }, | ||
| 258 | + canSecondApprove(row) { | ||
| 259 | + return !this.isSkipErpAuditSource(row) && row.djzt === '一级已审' | ||
| 260 | + }, | ||
| 261 | + formatLy(ly) { | ||
| 262 | + if (ly == null || ly === '') return '无' | ||
| 263 | + if (ly === '门店') return '门店(收银台)' | ||
| 264 | + if (ly === '抖音订单') return '抖音订单' | ||
| 265 | + return ly | ||
| 266 | + }, | ||
| 231 | // ✅ 原价:优先使用后端存储的 ydje(与收银台订单原价一致),无则用 收款+优惠 兼容旧数据 | 267 | // ✅ 原价:优先使用后端存储的 ydje(与收银台订单原价一致),无则用 收款+优惠 兼容旧数据 |
| 232 | getDisplayOriginalPrice(row) { | 268 | getDisplayOriginalPrice(row) { |
| 233 | const ydje = row.ydje != null && row.ydje !== ''; | 269 | const ydje = row.ydje != null && row.ydje !== ''; |
| @@ -392,10 +428,17 @@ | @@ -392,10 +428,17 @@ | ||
| 392 | }) | 428 | }) |
| 393 | }).catch(() => { }) | 429 | }).catch(() => { }) |
| 394 | }, | 430 | }, |
| 395 | - addOrUpdateHandle(id, isDetail) { | 431 | + openDetail(id) { |
| 432 | + if (!id) return | ||
| 433 | + this.detailVisible = true | ||
| 434 | + this.$nextTick(() => { | ||
| 435 | + if (this.$refs.NCCDetailView) this.$refs.NCCDetailView.init(id) | ||
| 436 | + }) | ||
| 437 | + }, | ||
| 438 | + addOrUpdateHandle(id) { | ||
| 396 | this.formVisible = true | 439 | this.formVisible = true |
| 397 | this.$nextTick(() => { | 440 | this.$nextTick(() => { |
| 398 | - this.$refs.NCCForm.init(id, isDetail) | 441 | + this.$refs.NCCForm.init(id, false) |
| 399 | }) | 442 | }) |
| 400 | }, | 443 | }, |
| 401 | exportData() { | 444 | exportData() { |
| @@ -428,6 +471,7 @@ | @@ -428,6 +471,7 @@ | ||
| 428 | }, | 471 | }, |
| 429 | refresh(isrRefresh) { | 472 | refresh(isrRefresh) { |
| 430 | this.formVisible = false | 473 | this.formVisible = false |
| 474 | + this.detailVisible = false | ||
| 431 | if (isrRefresh) this.reset() | 475 | if (isrRefresh) this.reset() |
| 432 | }, | 476 | }, |
| 433 | reset() { | 477 | reset() { |
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsthd/Form.vue
| 1 | -<template> | ||
| 2 | - <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="80%"> | 1 | +<template> |
| 2 | + <el-dialog :title="!dataForm.id ? '新建' : '编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="80%"> | ||
| 3 | <el-row :gutter="15" class="" > | 3 | <el-row :gutter="15" class="" > |
| 4 | - <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules"> | 4 | + <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :rules="rules"> |
| 5 | <el-col :span="12"> | 5 | <el-col :span="12"> |
| 6 | <el-form-item label="单据编号" prop="id"> | 6 | <el-form-item label="单据编号" prop="id"> |
| 7 | <el-input v-model="dataForm.id" placeholder="请输入" clearable readonly :style='{"width":"100%"}' > | 7 | <el-input v-model="dataForm.id" placeholder="请输入" clearable readonly :style='{"width":"100%"}' > |
| @@ -215,7 +215,7 @@ | @@ -215,7 +215,7 @@ | ||
| 215 | </el-row> | 215 | </el-row> |
| 216 | <span slot="footer" class="dialog-footer"> | 216 | <span slot="footer" class="dialog-footer"> |
| 217 | <el-button @click="visible = false">取 消</el-button> | 217 | <el-button @click="visible = false">取 消</el-button> |
| 218 | - <el-button type="primary" @click="dataFormSubmit()" v-if="!isDetail">确 定</el-button> | 218 | + <el-button type="primary" @click="dataFormSubmit()">确 定</el-button> |
| 219 | </span> | 219 | </span> |
| 220 | <!-- 序列号选择弹窗 --> | 220 | <!-- 序列号选择弹窗 --> |
| 221 | <SerialNumberSelect ref="serialNumberSelect" @confirm="handleSerialNumberSelect" /> | 221 | <SerialNumberSelect ref="serialNumberSelect" @confirm="handleSerialNumberSelect" /> |
| @@ -233,7 +233,6 @@ | @@ -233,7 +233,6 @@ | ||
| 233 | return { | 233 | return { |
| 234 | loading: false, | 234 | loading: false, |
| 235 | visible: false, | 235 | visible: false, |
| 236 | - isDetail: false, | ||
| 237 | dataForm: { | 236 | dataForm: { |
| 238 | id:'', | 237 | id:'', |
| 239 | id:undefined, | 238 | id:undefined, |
| @@ -324,10 +323,9 @@ | @@ -324,10 +323,9 @@ | ||
| 324 | goBack() { | 323 | goBack() { |
| 325 | this.$emit('refresh') | 324 | this.$emit('refresh') |
| 326 | }, | 325 | }, |
| 327 | - init(id, isDetail) { | 326 | + init(id) { |
| 328 | this.dataForm.id = id || 0; | 327 | this.dataForm.id = id || 0; |
| 329 | this.visible = true; | 328 | this.visible = true; |
| 330 | - this.isDetail = isDetail || false; | ||
| 331 | this.$nextTick(() => { | 329 | this.$nextTick(() => { |
| 332 | this.$refs['elForm'].resetFields(); | 330 | this.$refs['elForm'].resetFields(); |
| 333 | if (this.dataForm.id) { | 331 | if (this.dataForm.id) { |
| @@ -358,8 +356,11 @@ | @@ -358,8 +356,11 @@ | ||
| 358 | 356 | ||
| 359 | // 同步明细表的入库仓库与主表保持一致 | 357 | // 同步明细表的入库仓库与主表保持一致 |
| 360 | this.syncDetailWarehouses(); | 358 | this.syncDetailWarehouses(); |
| 361 | - // 计算总金额 | ||
| 362 | - this.updateTotalAmount(); | 359 | + // 主表退款金额 skje 以服务端为准(收银台选择的实退金额),不能用明细 je 合计覆盖, |
| 360 | + // 否则会出现列表 320、详情被算成 388 等不一致。 | ||
| 361 | + if (this.dataForm.skje == null || this.dataForm.skje === '') { | ||
| 362 | + this.updateTotalAmount(); | ||
| 363 | + } | ||
| 363 | }) | 364 | }) |
| 364 | } else { | 365 | } else { |
| 365 | // 新建时确保wtXsckdMxList为空数组 | 366 | // 新建时确保wtXsckdMxList为空数组 |
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsthd/detail-view.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-dialog | ||
| 3 | + title="销售退货单详情" | ||
| 4 | + :close-on-click-modal="false" | ||
| 5 | + :visible.sync="visible" | ||
| 6 | + class="NCC-dialog NCC-dialog_center xsthd-detail-dialog" | ||
| 7 | + lock-scroll | ||
| 8 | + width="1200px" | ||
| 9 | + top="6vh" | ||
| 10 | + @close="handleClose" | ||
| 11 | + > | ||
| 12 | + <div v-loading="loading" class="xsthd-detail-wrap"> | ||
| 13 | + <template v-if="detail"> | ||
| 14 | + <!-- 顶部:单号 + 状态 --> | ||
| 15 | + <div class="detail-top"> | ||
| 16 | + <div class="detail-top__id"> | ||
| 17 | + <i class="el-icon-document detail-top__icon detail-top__icon--primary" /> | ||
| 18 | + <span class="cell-nowrap">{{ cellText(detail.id) }}</span> | ||
| 19 | + </div> | ||
| 20 | + <el-tag :type="djztTagType" size="medium" effect="plain">{{ djztLabel }}</el-tag> | ||
| 21 | + </div> | ||
| 22 | + | ||
| 23 | + <!-- 退款金额(与列表一致,突出展示) --> | ||
| 24 | + <div class="refund-stat-card"> | ||
| 25 | + <div class="refund-stat-card__inner"> | ||
| 26 | + <i class="el-icon-coin refund-stat-card__coin" /> | ||
| 27 | + <div class="refund-stat-card__text"> | ||
| 28 | + <div class="refund-stat-card__label">退款金额(收银台实退)</div> | ||
| 29 | + <div class="refund-stat-card__value cell-nowrap">{{ formatMoneyCol(detail.skje) }}</div> | ||
| 30 | + </div> | ||
| 31 | + </div> | ||
| 32 | + <p class="refund-stat-card__hint"> | ||
| 33 | + <i class="el-icon-info" /> | ||
| 34 | + 与明细「金额」合计可能不一致(议价、部分退等以本金额为准) | ||
| 35 | + </p> | ||
| 36 | + </div> | ||
| 37 | + | ||
| 38 | + <el-descriptions | ||
| 39 | + title="基本信息" | ||
| 40 | + :column="2" | ||
| 41 | + border | ||
| 42 | + size="small" | ||
| 43 | + class="detail-descriptions" | ||
| 44 | + :label-style="{ width: '108px' }" | ||
| 45 | + > | ||
| 46 | + <el-descriptions-item label="单据日期"> | ||
| 47 | + <span class="cell-nowrap"> | ||
| 48 | + <i class="el-icon-date desc-icon desc-icon--primary" /> | ||
| 49 | + {{ formatDjrq(detail.djrq) }} | ||
| 50 | + </span> | ||
| 51 | + </el-descriptions-item> | ||
| 52 | + <el-descriptions-item label="单据类型"> | ||
| 53 | + <span class="cell-nowrap"> | ||
| 54 | + <i class="el-icon-tickets desc-icon desc-icon--info" /> | ||
| 55 | + {{ cellText(detail.djlx || '销售退货单') }} | ||
| 56 | + </span> | ||
| 57 | + </el-descriptions-item> | ||
| 58 | + <el-descriptions-item label="入库仓库"> | ||
| 59 | + <span class="cell-nowrap"> | ||
| 60 | + <i class="el-icon-s-home desc-icon desc-icon--muted" /> | ||
| 61 | + {{ cellText(detail.cjck) }} | ||
| 62 | + </span> | ||
| 63 | + </el-descriptions-item> | ||
| 64 | + <el-descriptions-item label="经手人"> | ||
| 65 | + <span class="cell-nowrap"> | ||
| 66 | + <i class="el-icon-user desc-icon desc-icon--primary" /> | ||
| 67 | + {{ cellText(detail.jsr) }} | ||
| 68 | + </span> | ||
| 69 | + </el-descriptions-item> | ||
| 70 | + </el-descriptions> | ||
| 71 | + | ||
| 72 | + <div class="detail-section-head"> | ||
| 73 | + <i class="el-icon-s-order detail-section-head__icon" /> | ||
| 74 | + <span>退货明细</span> | ||
| 75 | + <span class="detail-section-head__sub">(列表不换行展示)</span> | ||
| 76 | + </div> | ||
| 77 | + <el-table | ||
| 78 | + :data="detail.wtXsckdMxList || []" | ||
| 79 | + size="small" | ||
| 80 | + border | ||
| 81 | + stripe | ||
| 82 | + show-summary | ||
| 83 | + :summary-method="getSummaries" | ||
| 84 | + class="detail-mx-table" | ||
| 85 | + :empty-text="'无明细'" | ||
| 86 | + > | ||
| 87 | + <el-table-column type="index" width="52" label="#" align="center" /> | ||
| 88 | + <el-table-column label="入库仓库" min-width="118" show-overflow-tooltip> | ||
| 89 | + <template slot-scope="scope"> | ||
| 90 | + <span class="cell-nowrap mx-cell"> | ||
| 91 | + <i class="el-icon-location-outline mx-cell__icon mx-cell__icon--muted" /> | ||
| 92 | + {{ labelFromOptions(scope.row.ckck, cjckOptions) }} | ||
| 93 | + </span> | ||
| 94 | + </template> | ||
| 95 | + </el-table-column> | ||
| 96 | + <el-table-column label="商品" min-width="160" show-overflow-tooltip> | ||
| 97 | + <template slot-scope="scope"> | ||
| 98 | + <span class="cell-nowrap mx-cell"> | ||
| 99 | + <i class="el-icon-goods mx-cell__icon mx-cell__icon--primary" /> | ||
| 100 | + {{ cellText(scope.row.spmc) }} | ||
| 101 | + </span> | ||
| 102 | + </template> | ||
| 103 | + </el-table-column> | ||
| 104 | + <el-table-column prop="sl" label="数量" width="72" align="right"> | ||
| 105 | + <template slot-scope="scope"> | ||
| 106 | + <span class="cell-nowrap">{{ cellText(scope.row.sl) }}</span> | ||
| 107 | + </template> | ||
| 108 | + </el-table-column> | ||
| 109 | + <el-table-column prop="dj" label="单价" width="96" align="right"> | ||
| 110 | + <template slot-scope="scope"> | ||
| 111 | + <span class="cell-nowrap">{{ formatMoneyCol(scope.row.dj) }}</span> | ||
| 112 | + </template> | ||
| 113 | + </el-table-column> | ||
| 114 | + <el-table-column prop="je" label="金额" width="96" align="right"> | ||
| 115 | + <template slot-scope="scope"> | ||
| 116 | + <span class="cell-nowrap mx-cell__money">{{ formatMoneyCol(scope.row.je) }}</span> | ||
| 117 | + </template> | ||
| 118 | + </el-table-column> | ||
| 119 | + <el-table-column prop="description" label="备注" min-width="88" show-overflow-tooltip> | ||
| 120 | + <template slot-scope="scope"> | ||
| 121 | + <span class="cell-nowrap">{{ cellText(scope.row.description) }}</span> | ||
| 122 | + </template> | ||
| 123 | + </el-table-column> | ||
| 124 | + <el-table-column label="序列号" min-width="168"> | ||
| 125 | + <template slot-scope="scope"> | ||
| 126 | + <div v-if="scope.row.selectedSerialNumbers && scope.row.selectedSerialNumbers.length" class="sn-tags"> | ||
| 127 | + <el-tag | ||
| 128 | + v-for="(sn, idx) in scope.row.selectedSerialNumbers" | ||
| 129 | + :key="idx" | ||
| 130 | + size="mini" | ||
| 131 | + type="warning" | ||
| 132 | + class="sn-tag" | ||
| 133 | + >{{ sn }}</el-tag> | ||
| 134 | + </div> | ||
| 135 | + <span v-else class="text-muted">无</span> | ||
| 136 | + </template> | ||
| 137 | + </el-table-column> | ||
| 138 | + </el-table> | ||
| 139 | + | ||
| 140 | + <el-descriptions | ||
| 141 | + title="退款与审核" | ||
| 142 | + :column="2" | ||
| 143 | + border | ||
| 144 | + size="small" | ||
| 145 | + class="detail-descriptions detail-descriptions--footer" | ||
| 146 | + :label-style="{ width: '108px' }" | ||
| 147 | + > | ||
| 148 | + <el-descriptions-item label="退款账户"> | ||
| 149 | + <span class="cell-nowrap"> | ||
| 150 | + <i class="el-icon-bank-card desc-icon desc-icon--success" /> | ||
| 151 | + {{ labelFromOptions(detail.skzh, skzhOptions) }} | ||
| 152 | + </span> | ||
| 153 | + </el-descriptions-item> | ||
| 154 | + <el-descriptions-item label="审核人"> | ||
| 155 | + <span class="cell-nowrap"> | ||
| 156 | + <i class="el-icon-s-check desc-icon desc-icon--warning" /> | ||
| 157 | + {{ cellText(detail.shr) }} | ||
| 158 | + </span> | ||
| 159 | + </el-descriptions-item> | ||
| 160 | + <el-descriptions-item label="过账人"> | ||
| 161 | + <span class="cell-nowrap"> | ||
| 162 | + <i class="el-icon-s-promotion desc-icon desc-icon--info" /> | ||
| 163 | + {{ cellText(detail.gzr) }} | ||
| 164 | + </span> | ||
| 165 | + </el-descriptions-item> | ||
| 166 | + <el-descriptions-item label="备注" :span="2"> | ||
| 167 | + <span class="detail-bz">{{ cellText(detail.bz) }}</span> | ||
| 168 | + </el-descriptions-item> | ||
| 169 | + </el-descriptions> | ||
| 170 | + </template> | ||
| 171 | + <div v-else-if="!loading" class="detail-empty"> | ||
| 172 | + <i class="el-icon-warning-outline" /> | ||
| 173 | + <span>暂无数据</span> | ||
| 174 | + </div> | ||
| 175 | + </div> | ||
| 176 | + </el-dialog> | ||
| 177 | +</template> | ||
| 178 | + | ||
| 179 | +<script> | ||
| 180 | +import request from '@/utils/request' | ||
| 181 | +import { getDictionaryDataSelector } from '@/api/systemData/dictionary' | ||
| 182 | +import { previewDataInterface } from '@/api/systemData/dataInterface' | ||
| 183 | +import { dynamicText } from '@/filters' | ||
| 184 | + | ||
| 185 | +export default { | ||
| 186 | + name: 'WtXsthdDetailView', | ||
| 187 | + data() { | ||
| 188 | + return { | ||
| 189 | + visible: false, | ||
| 190 | + loading: false, | ||
| 191 | + detail: null, | ||
| 192 | + cjckOptions: [], | ||
| 193 | + skzhOptions: [] | ||
| 194 | + } | ||
| 195 | + }, | ||
| 196 | + computed: { | ||
| 197 | + djztLabel() { | ||
| 198 | + const z = this.detail && this.detail.djzt | ||
| 199 | + if (!z) return '待审核' | ||
| 200 | + return z | ||
| 201 | + }, | ||
| 202 | + djztTagType() { | ||
| 203 | + const z = this.detail && this.detail.djzt | ||
| 204 | + if (z === '已审核') return 'success' | ||
| 205 | + if (z === '一级已审') return '' | ||
| 206 | + if (z === '待审核' || !z) return 'warning' | ||
| 207 | + return 'info' | ||
| 208 | + } | ||
| 209 | + }, | ||
| 210 | + methods: { | ||
| 211 | + labelFromOptions(value, options) { | ||
| 212 | + if (value === null || value === undefined || value === '') return '无' | ||
| 213 | + const opts = options || [] | ||
| 214 | + let text = dynamicText(value, opts) | ||
| 215 | + if (text && text !== value) return text | ||
| 216 | + const row = opts.find( | ||
| 217 | + o => o.F_Id === value || String(o.F_Id) === String(value) || o.id === value || String(o.id) === String(value) | ||
| 218 | + ) | ||
| 219 | + if (row) return row.F_mdmc || row.fullName || value | ||
| 220 | + return text || String(value) | ||
| 221 | + }, | ||
| 222 | + cellText(v) { | ||
| 223 | + if (v === null || v === undefined || v === '') return '无' | ||
| 224 | + return v | ||
| 225 | + }, | ||
| 226 | + formatMoneyCol(v) { | ||
| 227 | + if (v === null || v === undefined || v === '') return '无' | ||
| 228 | + const n = Number(v) | ||
| 229 | + return isNaN(n) ? '无' : n.toFixed(2) | ||
| 230 | + }, | ||
| 231 | + formatDjrq(ts) { | ||
| 232 | + if (ts == null || ts === '') return '无' | ||
| 233 | + const d = new Date(typeof ts === 'number' ? ts : Number(ts)) | ||
| 234 | + if (isNaN(d.getTime())) return '无' | ||
| 235 | + const y = d.getFullYear() | ||
| 236 | + const m = String(d.getMonth() + 1).padStart(2, '0') | ||
| 237 | + const day = String(d.getDate()).padStart(2, '0') | ||
| 238 | + return `${y}-${m}-${day}` | ||
| 239 | + }, | ||
| 240 | + getSummaries(param) { | ||
| 241 | + const { columns, data } = param | ||
| 242 | + const sums = [] | ||
| 243 | + columns.forEach((column, index) => { | ||
| 244 | + if (index === 0) { | ||
| 245 | + sums[index] = '合计' | ||
| 246 | + return | ||
| 247 | + } | ||
| 248 | + if (column.property === 'sl') { | ||
| 249 | + sums[index] = data.reduce((t, row) => t + (parseFloat(row.sl) || 0), 0) | ||
| 250 | + } else if (column.property === 'je') { | ||
| 251 | + sums[index] = data | ||
| 252 | + .reduce((t, row) => t + (parseFloat(row.je) || 0), 0) | ||
| 253 | + .toFixed(2) | ||
| 254 | + } else { | ||
| 255 | + sums[index] = '' | ||
| 256 | + } | ||
| 257 | + }) | ||
| 258 | + return sums | ||
| 259 | + }, | ||
| 260 | + handleClose() { | ||
| 261 | + this.detail = null | ||
| 262 | + this.$emit('close') | ||
| 263 | + }, | ||
| 264 | + init(id) { | ||
| 265 | + if (!id) return | ||
| 266 | + this.visible = true | ||
| 267 | + this.loading = true | ||
| 268 | + this.detail = null | ||
| 269 | + request({ | ||
| 270 | + url: '/api/Extend/WtXsckd/' + id, | ||
| 271 | + method: 'get' | ||
| 272 | + }) | ||
| 273 | + .then(res => { | ||
| 274 | + this.detail = res.data || null | ||
| 275 | + if (this.detail && !this.detail.wtXsckdMxList) { | ||
| 276 | + this.$set(this.detail, 'wtXsckdMxList', []) | ||
| 277 | + } | ||
| 278 | + }) | ||
| 279 | + .catch(() => { | ||
| 280 | + this.$message.error('加载详情失败') | ||
| 281 | + this.visible = false | ||
| 282 | + }) | ||
| 283 | + .finally(() => { | ||
| 284 | + this.loading = false | ||
| 285 | + }) | ||
| 286 | + }, | ||
| 287 | + loadOptions() { | ||
| 288 | + previewDataInterface('681758216954053893').then(res => { | ||
| 289 | + this.cjckOptions = res.data || [] | ||
| 290 | + }) | ||
| 291 | + getDictionaryDataSelector('681761709836207365').then(res => { | ||
| 292 | + this.skzhOptions = res.data.list || [] | ||
| 293 | + }) | ||
| 294 | + } | ||
| 295 | + }, | ||
| 296 | + created() { | ||
| 297 | + this.loadOptions() | ||
| 298 | + } | ||
| 299 | +} | ||
| 300 | +</script> | ||
| 301 | + | ||
| 302 | +<style scoped lang="scss"> | ||
| 303 | +.cell-nowrap { | ||
| 304 | + white-space: nowrap; | ||
| 305 | +} | ||
| 306 | +.text-muted { | ||
| 307 | + color: #909399; | ||
| 308 | + font-size: 12px; | ||
| 309 | +} | ||
| 310 | + | ||
| 311 | +.xsthd-detail-wrap { | ||
| 312 | + min-height: 160px; | ||
| 313 | + margin-bottom: 50px; | ||
| 314 | +} | ||
| 315 | + | ||
| 316 | +.detail-top { | ||
| 317 | + display: flex; | ||
| 318 | + align-items: center; | ||
| 319 | + justify-content: space-between; | ||
| 320 | + flex-wrap: wrap; | ||
| 321 | + gap: 10px; | ||
| 322 | + margin-bottom: 14px; | ||
| 323 | + padding-bottom: 12px; | ||
| 324 | + border-bottom: 1px solid #ebeef5; | ||
| 325 | +} | ||
| 326 | +.detail-top__id { | ||
| 327 | + display: flex; | ||
| 328 | + align-items: center; | ||
| 329 | + gap: 8px; | ||
| 330 | + font-size: 15px; | ||
| 331 | + font-weight: 600; | ||
| 332 | + color: #303133; | ||
| 333 | +} | ||
| 334 | +.detail-top__icon { | ||
| 335 | + font-size: 18px; | ||
| 336 | +} | ||
| 337 | +.detail-top__icon--primary { | ||
| 338 | + color: #409eff; | ||
| 339 | +} | ||
| 340 | + | ||
| 341 | +/* 统计卡片:高度 100px、内边距 12px、圆角 12px(与项目规范一致) */ | ||
| 342 | +.refund-stat-card { | ||
| 343 | + height: 100px; | ||
| 344 | + padding: 12px; | ||
| 345 | + border-radius: 12px; | ||
| 346 | + background: linear-gradient(135deg, #ecf5ff 0%, #f5f9ff 100%); | ||
| 347 | + border: 1px solid #d9ecff; | ||
| 348 | + margin-bottom: 16px; | ||
| 349 | + box-sizing: border-box; | ||
| 350 | + display: flex; | ||
| 351 | + flex-direction: column; | ||
| 352 | + justify-content: center; | ||
| 353 | +} | ||
| 354 | +.refund-stat-card__inner { | ||
| 355 | + display: flex; | ||
| 356 | + align-items: center; | ||
| 357 | + gap: 14px; | ||
| 358 | +} | ||
| 359 | +.refund-stat-card__coin { | ||
| 360 | + font-size: 36px; | ||
| 361 | + color: #409eff; | ||
| 362 | + line-height: 1; | ||
| 363 | +} | ||
| 364 | +.refund-stat-card__label { | ||
| 365 | + font-size: 12px; | ||
| 366 | + color: #909399; | ||
| 367 | + margin-bottom: 4px; | ||
| 368 | +} | ||
| 369 | +.refund-stat-card__value { | ||
| 370 | + font-size: 22px; | ||
| 371 | + font-weight: 600; | ||
| 372 | + color: #303133; | ||
| 373 | + letter-spacing: 0.02em; | ||
| 374 | +} | ||
| 375 | +.refund-stat-card__hint { | ||
| 376 | + margin: 10px 0 0; | ||
| 377 | + font-size: 12px; | ||
| 378 | + color: #909399; | ||
| 379 | + line-height: 1.4; | ||
| 380 | + display: flex; | ||
| 381 | + align-items: flex-start; | ||
| 382 | + gap: 4px; | ||
| 383 | +} | ||
| 384 | +.refund-stat-card__hint .el-icon-info { | ||
| 385 | + margin-top: 2px; | ||
| 386 | + color: #c0c4cc; | ||
| 387 | +} | ||
| 388 | + | ||
| 389 | +.detail-descriptions { | ||
| 390 | + margin-bottom: 8px; | ||
| 391 | +} | ||
| 392 | +.detail-descriptions--footer { | ||
| 393 | + margin-top: 14px; | ||
| 394 | +} | ||
| 395 | +.desc-icon { | ||
| 396 | + margin-right: 6px; | ||
| 397 | + font-size: 14px; | ||
| 398 | + vertical-align: -1px; | ||
| 399 | +} | ||
| 400 | +.desc-icon--primary { | ||
| 401 | + color: #409eff; | ||
| 402 | +} | ||
| 403 | +.desc-icon--success { | ||
| 404 | + color: #67c23a; | ||
| 405 | +} | ||
| 406 | +.desc-icon--warning { | ||
| 407 | + color: #e6a23c; | ||
| 408 | +} | ||
| 409 | +.desc-icon--info { | ||
| 410 | + color: #909399; | ||
| 411 | +} | ||
| 412 | +.desc-icon--muted { | ||
| 413 | + color: #c0c4cc; | ||
| 414 | +} | ||
| 415 | + | ||
| 416 | +.detail-section-head { | ||
| 417 | + display: flex; | ||
| 418 | + align-items: center; | ||
| 419 | + gap: 6px; | ||
| 420 | + margin: 16px 0 10px; | ||
| 421 | + font-size: 14px; | ||
| 422 | + font-weight: 600; | ||
| 423 | + color: #303133; | ||
| 424 | +} | ||
| 425 | +.detail-section-head__icon { | ||
| 426 | + color: #409eff; | ||
| 427 | + font-size: 16px; | ||
| 428 | +} | ||
| 429 | +.detail-section-head__sub { | ||
| 430 | + font-size: 12px; | ||
| 431 | + font-weight: normal; | ||
| 432 | + color: #909399; | ||
| 433 | +} | ||
| 434 | + | ||
| 435 | +.detail-mx-table { | ||
| 436 | + width: 100%; | ||
| 437 | +} | ||
| 438 | +.mx-cell { | ||
| 439 | + display: inline-flex; | ||
| 440 | + align-items: center; | ||
| 441 | + max-width: 100%; | ||
| 442 | +} | ||
| 443 | +.mx-cell__icon { | ||
| 444 | + margin-right: 4px; | ||
| 445 | + flex-shrink: 0; | ||
| 446 | + font-size: 14px; | ||
| 447 | +} | ||
| 448 | +.mx-cell__icon--primary { | ||
| 449 | + color: #409eff; | ||
| 450 | +} | ||
| 451 | +.mx-cell__icon--muted { | ||
| 452 | + color: #909399; | ||
| 453 | +} | ||
| 454 | +.mx-cell__money { | ||
| 455 | + color: #303133; | ||
| 456 | + font-weight: 500; | ||
| 457 | +} | ||
| 458 | + | ||
| 459 | +.sn-tags { | ||
| 460 | + display: flex; | ||
| 461 | + flex-wrap: wrap; | ||
| 462 | + gap: 4px; | ||
| 463 | + align-items: center; | ||
| 464 | +} | ||
| 465 | +.sn-tag { | ||
| 466 | + margin: 0 !important; | ||
| 467 | +} | ||
| 468 | + | ||
| 469 | +.detail-bz { | ||
| 470 | + white-space: pre-wrap; | ||
| 471 | + word-break: break-all; | ||
| 472 | + line-height: 1.5; | ||
| 473 | + color: #606266; | ||
| 474 | +} | ||
| 475 | + | ||
| 476 | +.detail-empty { | ||
| 477 | + display: flex; | ||
| 478 | + align-items: center; | ||
| 479 | + justify-content: center; | ||
| 480 | + gap: 8px; | ||
| 481 | + padding: 40px; | ||
| 482 | + color: #909399; | ||
| 483 | + font-size: 14px; | ||
| 484 | +} | ||
| 485 | +.detail-empty .el-icon-warning-outline { | ||
| 486 | + font-size: 20px; | ||
| 487 | + color: #e6a23c; | ||
| 488 | +} | ||
| 489 | + | ||
| 490 | +/* 操作区左对齐 */ | ||
| 491 | +.xsthd-detail-footer { | ||
| 492 | + text-align: left; | ||
| 493 | +} | ||
| 494 | +</style> |
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsthd/index.vue
| @@ -133,6 +133,7 @@ | @@ -133,6 +133,7 @@ | ||
| 133 | </div> | 133 | </div> |
| 134 | </div> | 134 | </div> |
| 135 | <NCC-Form v-if="formVisible" ref="NCCForm" @refresh="refresh" /> | 135 | <NCC-Form v-if="formVisible" ref="NCCForm" @refresh="refresh" /> |
| 136 | + <DetailView v-if="detailVisible" ref="NCCDetailView" @close="detailVisible = false" /> | ||
| 136 | <ExportBox v-if="exportBoxVisible" ref="ExportBox" @download="download" /> | 137 | <ExportBox v-if="exportBoxVisible" ref="ExportBox" @download="download" /> |
| 137 | </div> | 138 | </div> |
| 138 | </template> | 139 | </template> |
| @@ -140,10 +141,11 @@ | @@ -140,10 +141,11 @@ | ||
| 140 | import request from '@/utils/request' | 141 | import request from '@/utils/request' |
| 141 | import { getDictionaryDataSelector } from '@/api/systemData/dictionary' | 142 | import { getDictionaryDataSelector } from '@/api/systemData/dictionary' |
| 142 | import NCCForm from './Form' | 143 | import NCCForm from './Form' |
| 144 | + import DetailView from './detail-view' | ||
| 143 | import ExportBox from './ExportBox' | 145 | import ExportBox from './ExportBox' |
| 144 | import { previewDataInterface } from '@/api/systemData/dataInterface' | 146 | import { previewDataInterface } from '@/api/systemData/dataInterface' |
| 145 | export default { | 147 | export default { |
| 146 | - components: { NCCForm, ExportBox }, | 148 | + components: { NCCForm, DetailView, ExportBox }, |
| 147 | data() { | 149 | data() { |
| 148 | return { | 150 | return { |
| 149 | showAll: false, | 151 | showAll: false, |
| @@ -171,6 +173,7 @@ | @@ -171,6 +173,7 @@ | ||
| 171 | sidx: "", | 173 | sidx: "", |
| 172 | }, | 174 | }, |
| 173 | formVisible: false, | 175 | formVisible: false, |
| 176 | + detailVisible: false, | ||
| 174 | exportBoxVisible: false, | 177 | exportBoxVisible: false, |
| 175 | columnList: [ | 178 | columnList: [ |
| 176 | { prop: 'id', label: '单据编号' }, | 179 | { prop: 'id', label: '单据编号' }, |
| @@ -325,9 +328,16 @@ | @@ -325,9 +328,16 @@ | ||
| 325 | }).catch(() => { }) | 328 | }).catch(() => { }) |
| 326 | }, | 329 | }, |
| 327 | addOrUpdateHandle(id, isDetail) { | 330 | addOrUpdateHandle(id, isDetail) { |
| 331 | + if (isDetail) { | ||
| 332 | + this.detailVisible = true | ||
| 333 | + this.$nextTick(() => { | ||
| 334 | + if (this.$refs.NCCDetailView) this.$refs.NCCDetailView.init(id) | ||
| 335 | + }) | ||
| 336 | + return | ||
| 337 | + } | ||
| 328 | this.formVisible = true | 338 | this.formVisible = true |
| 329 | this.$nextTick(() => { | 339 | this.$nextTick(() => { |
| 330 | - this.$refs.NCCForm.init(id, isDetail) | 340 | + this.$refs.NCCForm.init(id) |
| 331 | }) | 341 | }) |
| 332 | }, | 342 | }, |
| 333 | exportData() { | 343 | exportData() { |
| @@ -360,6 +370,7 @@ | @@ -360,6 +370,7 @@ | ||
| 360 | }, | 370 | }, |
| 361 | refresh(isrRefresh) { | 371 | refresh(isrRefresh) { |
| 362 | this.formVisible = false | 372 | this.formVisible = false |
| 373 | + this.detailVisible = false | ||
| 363 | if (isrRefresh) this.reset() | 374 | if (isrRefresh) this.reset() |
| 364 | }, | 375 | }, |
| 365 | reset() { | 376 | reset() { |
Antis.Erp.Plat/douyin/DouyinLogistics.API/Services/OrderService.cs
| @@ -1307,7 +1307,8 @@ public class OrderService | @@ -1307,7 +1307,8 @@ public class OrderService | ||
| 1307 | djlx = "销售出库单", | 1307 | djlx = "销售出库单", |
| 1308 | kh = defaultKh, | 1308 | kh = defaultKh, |
| 1309 | gys = "", | 1309 | gys = "", |
| 1310 | - djzt = "待审核", | 1310 | + // 抖音发货带出单不走 ERP 二级审核,与收银台一致视为已生效 |
| 1311 | + djzt = "已审核", | ||
| 1311 | ly = "抖音订单", | 1312 | ly = "抖音订单", |
| 1312 | skmx = "", | 1313 | skmx = "", |
| 1313 | wtXsckdMxList = salesOrderDetails | 1314 | wtXsckdMxList = salesOrderDetails |
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtXsckdService.cs
| @@ -336,7 +336,8 @@ namespace NCC.Extend.WtXsckd | @@ -336,7 +336,8 @@ namespace NCC.Extend.WtXsckd | ||
| 336 | 336 | ||
| 337 | bz = xsckd.Bz, | 337 | bz = xsckd.Bz, |
| 338 | djlx = xsckd.Djlx, | 338 | djlx = xsckd.Djlx, |
| 339 | - djzt = xsckd.Djzt | 339 | + djzt = xsckd.Djzt, |
| 340 | + ly = xsckd.Ly | ||
| 340 | }).MergeTable().OrderBy(sidx + " " + input.sort).ToPagedListAsync(input.currentPage, input.pageSize); | 341 | }).MergeTable().OrderBy(sidx + " " + input.sort).ToPagedListAsync(input.currentPage, input.pageSize); |
| 341 | var pageRows = data.list?.ToList() ?? new List<WtXsckdListOutput>(); | 342 | var pageRows = data.list?.ToList() ?? new List<WtXsckdListOutput>(); |
| 342 | await EnrichWtXsckdListWarehouseDisplayAsync(pageRows); | 343 | await EnrichWtXsckdListWarehouseDisplayAsync(pageRows); |
| @@ -973,7 +974,8 @@ namespace NCC.Extend.WtXsckd | @@ -973,7 +974,8 @@ namespace NCC.Extend.WtXsckd | ||
| 973 | gys = SqlFunc.Subqueryable<WtGysEntity>().Where(u => u.Id == xsckd.Gys).Select(u => u.Gysmc), | 974 | gys = SqlFunc.Subqueryable<WtGysEntity>().Where(u => u.Id == xsckd.Gys).Select(u => u.Gysmc), |
| 974 | bz = xsckd.Bz, | 975 | bz = xsckd.Bz, |
| 975 | djlx = xsckd.Djlx, | 976 | djlx = xsckd.Djlx, |
| 976 | - djzt = xsckd.Djzt | 977 | + djzt = xsckd.Djzt, |
| 978 | + ly = xsckd.Ly | ||
| 977 | }).MergeTable().OrderBy(sidx + " " + input.sort).ToListAsync(); | 979 | }).MergeTable().OrderBy(sidx + " " + input.sort).ToListAsync(); |
| 978 | await EnrichWtXsckdListWarehouseDisplayAsync(data); | 980 | await EnrichWtXsckdListWarehouseDisplayAsync(data); |
| 979 | return data; | 981 | return data; |
| @@ -1137,6 +1139,8 @@ namespace NCC.Extend.WtXsckd | @@ -1137,6 +1139,8 @@ namespace NCC.Extend.WtXsckd | ||
| 1137 | EnsureBjhcbColumn(); | 1139 | EnsureBjhcbColumn(); |
| 1138 | var oldHeader = await _db.Queryable<WtXsckdEntity>().FirstAsync(p => p.Id == id); | 1140 | var oldHeader = await _db.Queryable<WtXsckdEntity>().FirstAsync(p => p.Id == id); |
| 1139 | var oldMxList = await _db.Queryable<WtXsckdMxEntity>().Where(u => u.Djbh == id).ToListAsync(); | 1141 | var oldMxList = await _db.Queryable<WtXsckdMxEntity>().Where(u => u.Djbh == id).ToListAsync(); |
| 1142 | + if (IsSalesOutboundSkipErpAudit(oldHeader)) | ||
| 1143 | + throw NCCException.Bah("收银台或抖音等外部来源的销售出库单不允许在此修改"); | ||
| 1140 | var entity = input.Adapt<WtXsckdEntity>(); | 1144 | var entity = input.Adapt<WtXsckdEntity>(); |
| 1141 | entity.Bjsx = input.bjsx; | 1145 | entity.Bjsx = input.bjsx; |
| 1142 | 1146 | ||
| @@ -2129,6 +2133,26 @@ ORDER BY t.`商品编号`;"; | @@ -2129,6 +2133,26 @@ ORDER BY t.`商品编号`;"; | ||
| 2129 | } | 2133 | } |
| 2130 | 2134 | ||
| 2131 | /// <summary> | 2135 | /// <summary> |
| 2136 | + /// 销售出库单是否跳过 ERP 二级审核:收银台「门店」、抖音「抖音订单/抖音抓单」、或备注为抖音发货脚本格式(抖音订单:…)。 | ||
| 2137 | + /// </summary> | ||
| 2138 | + private static bool IsSalesOutboundSkipErpAudit(WtXsckdEntity entity) | ||
| 2139 | + { | ||
| 2140 | + if (entity == null) return false; | ||
| 2141 | + if (!string.Equals(entity.Djlx, "销售出库单", StringComparison.Ordinal)) return false; | ||
| 2142 | + var ly = entity.Ly?.Trim(); | ||
| 2143 | + if (!string.IsNullOrEmpty(ly)) | ||
| 2144 | + { | ||
| 2145 | + if (string.Equals(ly, "门店", StringComparison.Ordinal)) return true; | ||
| 2146 | + if (string.Equals(ly, "抖音订单", StringComparison.Ordinal)) return true; | ||
| 2147 | + if (string.Equals(ly, "抖音抓单", StringComparison.Ordinal)) return true; | ||
| 2148 | + } | ||
| 2149 | + var bz = entity.Bz?.Trim(); | ||
| 2150 | + if (!string.IsNullOrEmpty(bz) && bz.StartsWith("抖音订单:", StringComparison.Ordinal)) | ||
| 2151 | + return true; | ||
| 2152 | + return false; | ||
| 2153 | + } | ||
| 2154 | + | ||
| 2155 | + /// <summary> | ||
| 2132 | /// 通用两级审核逻辑:根据 wt_shrysz 配置自动适配单级/两级审批 | 2156 | /// 通用两级审核逻辑:根据 wt_shrysz 配置自动适配单级/两级审批 |
| 2133 | /// </summary> | 2157 | /// </summary> |
| 2134 | [NonAction] | 2158 | [NonAction] |
| @@ -2272,11 +2296,15 @@ ORDER BY t.`商品编号`;"; | @@ -2272,11 +2296,15 @@ ORDER BY t.`商品编号`;"; | ||
| 2272 | } | 2296 | } |
| 2273 | 2297 | ||
| 2274 | /// <summary> | 2298 | /// <summary> |
| 2275 | - /// 审核销售出库单(支持两级审核) | 2299 | + /// 审核销售出库单(支持两级审核)。收银台「门店」、抖音「抖音订单」等外部来源无需在此审核。 |
| 2276 | /// </summary> | 2300 | /// </summary> |
| 2301 | + /// <param name="id">销售出库单主键</param> | ||
| 2277 | [HttpPost("ApproveSalesOutbound/{id}")] | 2302 | [HttpPost("ApproveSalesOutbound/{id}")] |
| 2278 | public async Task<dynamic> ApproveSalesOutbound(string id) | 2303 | public async Task<dynamic> ApproveSalesOutbound(string id) |
| 2279 | { | 2304 | { |
| 2305 | + var header = await _db.Queryable<WtXsckdEntity>().FirstAsync(p => p.Id == id); | ||
| 2306 | + if (header != null && IsSalesOutboundSkipErpAudit(header)) | ||
| 2307 | + return new { success = false, message = "收银台或抖音等外部来源的销售出库单无需在此审核" }; | ||
| 2280 | return await ApproveDocument(id, "销售出库单"); | 2308 | return await ApproveDocument(id, "销售出库单"); |
| 2281 | } | 2309 | } |
| 2282 | 2310 |
Antis.Erp.Plat/sy/settlement.html
| @@ -967,6 +967,10 @@ | @@ -967,6 +967,10 @@ | ||
| 967 | "bz": "", | 967 | "bz": "", |
| 968 | // 单据类型 | 968 | // 单据类型 |
| 969 | "djlx": "销售出库单", | 969 | "djlx": "销售出库单", |
| 970 | + // 单据来源:与 ERP 后台「门店(收银台)」一致,用于免审、仅查看 | ||
| 971 | + "ly": "门店", | ||
| 972 | + // 收银台成交即生效,不走 ERP 二级审核 | ||
| 973 | + "djzt": "已审核", | ||
| 970 | // 会员手机号码 | 974 | // 会员手机号码 |
| 971 | "hysjh": "", | 975 | "hysjh": "", |
| 972 | // 销售出库单明细列表 | 976 | // 销售出库单明细列表 |
| @@ -2469,6 +2473,8 @@ | @@ -2469,6 +2473,8 @@ | ||
| 2469 | this.info.zdr = this.selectedCashier; | 2473 | this.info.zdr = this.selectedCashier; |
| 2470 | this.info.djrq = new Date().toISOString(); // 确保日期时间正确 | 2474 | this.info.djrq = new Date().toISOString(); // 确保日期时间正确 |
| 2471 | delete this.info.id; // 让后端生成ID | 2475 | delete this.info.id; // 让后端生成ID |
| 2476 | + this.info.ly = '门店'; | ||
| 2477 | + this.info.djzt = '已审核'; | ||
| 2472 | 2478 | ||
| 2473 | axios({ | 2479 | axios({ |
| 2474 | url: this.baseUrl + "/api/Extend/wtxsckd", | 2480 | url: this.baseUrl + "/api/Extend/wtxsckd", |
| @@ -2785,6 +2791,9 @@ | @@ -2785,6 +2791,9 @@ | ||
| 2785 | } | 2791 | } |
| 2786 | 2792 | ||
| 2787 | delete orderData.id; // 让后端生成ID | 2793 | delete orderData.id; // 让后端生成ID |
| 2794 | + // 与 info 一致:收银台固定来源与状态(避免 spread 遗漏或被覆盖) | ||
| 2795 | + orderData.ly = '门店'; | ||
| 2796 | + orderData.djzt = '已审核'; | ||
| 2788 | 2797 | ||
| 2789 | console.log(`✅ 创建${documentType},商品数量: ${items.length},订单金额: ${groupTotalAmount.toFixed(2)}`); | 2798 | console.log(`✅ 创建${documentType},商品数量: ${items.length},订单金额: ${groupTotalAmount.toFixed(2)}`); |
| 2790 | 2799 |