Commit 27fb1711094f8eee3fea27ec6cc2313ad5a0885a

Authored by “wangming”
1 parent d4a6cf68

feat(erp): WtAccount 与收款账户展示,多模块表单/收银与后端联动

Made-with: Cursor
Showing 118 changed files with 3859 additions and 1255 deletions
Antis.Erp.Plat/antis-ncc-admin/src/api/extend/wtAccount.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function getAccountSelector(storeId) {
  4 + const data = {}
  5 + if (storeId) data.storeId = storeId
  6 + return request({
  7 + url: '/api/Extend/WtAccount/Selector',
  8 + method: 'GET',
  9 + data
  10 + })
  11 +}
  12 +
  13 +export function getAccountList(params) {
  14 + return request({
  15 + url: '/api/Extend/WtAccount',
  16 + method: 'GET',
  17 + data: params
  18 + })
  19 +}
  20 +
  21 +export function getAccountInfo(id) {
  22 + return request({
  23 + url: '/api/Extend/WtAccount/' + id,
  24 + method: 'GET'
  25 + })
  26 +}
  27 +
  28 +export function createAccount(data) {
  29 + return request({
  30 + url: '/api/Extend/WtAccount',
  31 + method: 'POST',
  32 + data
  33 + })
  34 +}
  35 +
  36 +export function updateAccount(id, data) {
  37 + return request({
  38 + url: '/api/Extend/WtAccount/' + id,
  39 + method: 'PUT',
  40 + data
  41 + })
  42 +}
  43 +
  44 +export function deleteAccount(id) {
  45 + return request({
  46 + url: '/api/Extend/WtAccount/' + id,
  47 + method: 'DELETE'
  48 + })
  49 +}
  50 +
  51 +export function batchRemoveAccount(ids) {
  52 + return request({
  53 + url: '/api/Extend/WtAccount/batchRemove',
  54 + method: 'POST',
  55 + data: ids
  56 + })
  57 +}
  58 +
  59 +export function getAccountCategories() {
  60 + return request({
  61 + url: '/api/Extend/WtAccount/Categories',
  62 + method: 'GET'
  63 + })
  64 +}
  65 +
  66 +export function exportAccount(params) {
  67 + return request({
  68 + url: '/api/Extend/WtAccount/Actions/Export',
  69 + method: 'GET',
  70 + data: params
  71 + })
  72 +}
... ...
Antis.Erp.Plat/antis-ncc-admin/src/utils/wtComboSkzhDisplay.js
... ... @@ -15,7 +15,7 @@ export function resolveSkzhDictionaryLabel(id, options) {
15 15 return oid === sid || ofid === sid
16 16 })
17 17 if (!row) return ''
18   - const name = (row.fullName || row.F_FullName || row.F_mdmc || '').trim()
  18 + const name = (row.fullName || row.accountName || row.F_FullName || row.F_mdmc || '').trim()
19 19 return name || ''
20 20 }
21 21  
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtBjdbd/Form.vue
... ... @@ -290,10 +290,10 @@
290 290 </template>
291 291 <script>
292 292 import request from '@/utils/request'
293   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
294 293 import { previewDataInterface } from '@/api/systemData/dataInterface'
295 294 import BarcodeSelect from '../wtCgrkd/BarcodeSelect.vue'
296 295 import SerialNumberSelect from './SerialNumberSelect.vue'
  296 + import { getAccountSelector } from '@/api/extend/wtAccount'
297 297 export default {
298 298 components: { BarcodeSelect, SerialNumberSelect },
299 299 props: [],
... ... @@ -657,7 +657,7 @@
657 657 });
658 658 },
659 659 getskzhOptions(){
660   - getDictionaryDataSelector('681761709836207365').then(res => {
  660 + getAccountSelector().then(res => {
661 661 this.skzhOptions = res.data.list
662 662 });
663 663 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtBjdbd/index.vue
... ... @@ -217,10 +217,10 @@
217 217 </template>
218 218 <script>
219 219 import request from '@/utils/request'
220   -import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
221 220 import NCCForm from './Form'
222 221 import ExportBox from './ExportBox'
223 222 import { previewDataInterface } from '@/api/systemData/dataInterface'
  223 +import { getAccountSelector } from '@/api/extend/wtAccount'
224 224  
225 225 export default {
226 226 components: { NCCForm, ExportBox },
... ... @@ -321,7 +321,7 @@ export default {
321 321 })
322 322 },
323 323 getskzhOptions() {
324   - getDictionaryDataSelector('681761709836207365').then(res => {
  324 + getAccountSelector().then(res => {
325 325 this.skzhOptions = res.data.list
326 326 })
327 327 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtBsd/Form.vue
... ... @@ -267,10 +267,10 @@
267 267 </template>
268 268 <script>
269 269 import request from '@/utils/request'
270   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
271 270 import { previewDataInterface } from '@/api/systemData/dataInterface'
272 271 import BarcodeSelect from '../wtCgrkd/BarcodeSelect.vue'
273 272 import SerialNumberSelect from './SerialNumberSelect.vue'
  273 + import { getAccountSelector } from '@/api/extend/wtAccount'
274 274 export default {
275 275 components: { BarcodeSelect, SerialNumberSelect },
276 276 props: [],
... ... @@ -583,7 +583,7 @@
583 583 });
584 584 },
585 585 getskzhOptions(){
586   - getDictionaryDataSelector('681761709836207365').then(res => {
  586 + getAccountSelector().then(res => {
587 587 this.skzhOptions = res.data.list
588 588 });
589 589 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtBsd/index.vue
... ... @@ -144,10 +144,10 @@
144 144 </template>
145 145 <script>
146 146 import request from '@/utils/request'
147   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
148 147 import NCCForm from './Form'
149 148 import ExportBox from './ExportBox'
150 149 import { previewDataInterface } from '@/api/systemData/dataInterface'
  150 + import { getAccountSelector } from '@/api/extend/wtAccount'
151 151 export default {
152 152 components: { NCCForm, ExportBox },
153 153 data() {
... ... @@ -218,7 +218,7 @@
218 218 });
219 219 },
220 220 getskzhOptions(){
221   - getDictionaryDataSelector('681761709836207365').then(res => {
  221 + getAccountSelector().then(res => {
222 222 this.skzhOptions = res.data.list
223 223 });
224 224 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtByd/Form.vue
... ... @@ -267,10 +267,10 @@
267 267 </template>
268 268 <script>
269 269 import request from '@/utils/request'
270   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
271 270 import { previewDataInterface } from '@/api/systemData/dataInterface'
272 271 import BarcodeSelect from '../wtCgrkd/BarcodeSelect.vue'
273 272 import SerialNumberSelect from './SerialNumberSelect.vue'
  273 + import { getAccountSelector } from '@/api/extend/wtAccount'
274 274 export default {
275 275 components: { BarcodeSelect, SerialNumberSelect },
276 276 props: [],
... ... @@ -583,7 +583,7 @@
583 583 });
584 584 },
585 585 getskzhOptions(){
586   - getDictionaryDataSelector('681761709836207365').then(res => {
  586 + getAccountSelector().then(res => {
587 587 this.skzhOptions = res.data.list
588 588 });
589 589 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtByd/index.vue
... ... @@ -144,10 +144,10 @@
144 144 </template>
145 145 <script>
146 146 import request from '@/utils/request'
147   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
148 147 import NCCForm from './Form'
149 148 import ExportBox from './ExportBox'
150 149 import { previewDataInterface } from '@/api/systemData/dataInterface'
  150 + import { getAccountSelector } from '@/api/extend/wtAccount'
151 151 export default {
152 152 components: { NCCForm, ExportBox },
153 153 data() {
... ... @@ -218,7 +218,7 @@
218 218 });
219 219 },
220 220 getskzhOptions(){
221   - getDictionaryDataSelector('681761709836207365').then(res => {
  221 + getAccountSelector().then(res => {
222 222 this.skzhOptions = res.data.list
223 223 });
224 224 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCgrkd/Form.vue
... ... @@ -206,9 +206,9 @@
206 206 </template>
207 207 <script>
208 208 import request from '@/utils/request'
209   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
210 209 import { previewDataInterface } from '@/api/systemData/dataInterface'
211 210 import BarcodeSelectWithScan from './BarcodeSelectWithScan.vue'
  211 + import { getAccountSelector } from '@/api/extend/wtAccount'
212 212 export default {
213 213 components: { BarcodeSelect: BarcodeSelectWithScan },
214 214 props: [],
... ... @@ -352,7 +352,7 @@ setFullName(item,row){
352 352 this.productQuery = val;
353 353 },
354 354 getskzhOptions(){
355   - getDictionaryDataSelector('681761709836207365').then(res => {
  355 + getAccountSelector().then(res => {
356 356 this.skzhOptions = res.data.list
357 357 });
358 358 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCgrkd/detail-view.vue
... ... @@ -173,9 +173,9 @@
173 173  
174 174 <script>
175 175 import request from '@/utils/request'
176   -import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
177 176 import { previewDataInterface } from '@/api/systemData/dataInterface'
178 177 import { dynamicText } from '@/filters'
  178 +import { getAccountSelector } from '@/api/extend/wtAccount'
179 179  
180 180 export default {
181 181 name: 'WtCgrkdDetailView',
... ... @@ -295,7 +295,7 @@ export default {
295 295 previewDataInterface('681758216954053893').then(res => {
296 296 this.rkckOptions = res.data || []
297 297 })
298   - getDictionaryDataSelector('681761709836207365').then(res => {
  298 + getAccountSelector().then(res => {
299 299 this.skzhOptions = res.data.list || []
300 300 })
301 301 request({
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCgrkd/index.vue
... ... @@ -139,12 +139,12 @@
139 139 </template>
140 140 <script>
141 141 import request from '@/utils/request'
142   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
143 142 import NCCForm from './Form'
144 143 import DetailView from './detail-view'
145 144 import ExportBox from './ExportBox'
146 145 import { previewDataInterface } from '@/api/systemData/dataInterface'
147 146 import { promptApprovalRemark, postApprovePurchaseInbound, postRejectGeneric } from '@/utils/wtRejectApproval'
  147 + import { getAccountSelector } from '@/api/extend/wtAccount'
148 148 export default {
149 149 components: { NCCForm, DetailView, ExportBox },
150 150 data() {
... ... @@ -221,7 +221,7 @@
221 221 });
222 222 },
223 223 getskzhOptions(){
224   - getDictionaryDataSelector('681761709836207365').then(res => {
  224 + getAccountSelector().then(res => {
225 225 this.skzhOptions = res.data.list
226 226 });
227 227 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCgthd/Form.vue
1 1 <template>
2   - <el-dialog :title="isNew ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="80%">
  2 + <el-dialog :title="isNew ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="80%" append-to-body>
3 3 <el-row :gutter="15" class="" >
4 4 <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules">
5 5 <el-col :span="12">
... ... @@ -187,8 +187,20 @@
187 187 </el-col> -->
188 188 <el-col :span="8">
189 189 <el-form-item label="退款账户" prop="skzh">
190   - <el-select v-model="dataForm.skzh" placeholder="请选择" clearable :style='{"width":"100%"}' filterable >
191   - <el-option v-for="(item, index) in skzhOptions" :key="index" :label="item.fullName" :value="item.id" ></el-option>
  190 + <el-select
  191 + v-model="dataForm.skzh"
  192 + placeholder="请选择"
  193 + clearable
  194 + :style='{"width":"100%"}'
  195 + filterable
  196 + popper-append-to-body
  197 + >
  198 + <el-option
  199 + v-for="(item, index) in skzhOptions"
  200 + :key="item.id != null ? String(item.id) : index"
  201 + :label="item.fullName || item.accountName || item.accountCode || '账户'"
  202 + :value="item.id"
  203 + />
192 204 </el-select>
193 205 </el-form-item>
194 206 </el-col>
... ... @@ -242,10 +254,10 @@
242 254 </template>
243 255 <script>
244 256 import request from '@/utils/request'
245   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
246 257 import { previewDataInterface } from '@/api/systemData/dataInterface'
247 258 import SerialNumberSelect from '../wtXsckd/SerialNumberSelect.vue'
248 259 import PurchaseInboundOrderSelect from './PurchaseInboundOrderSelect.vue'
  260 + import { getAccountSelector } from '@/api/extend/wtAccount'
249 261 export default {
250 262 components: { SerialNumberSelect, PurchaseInboundOrderSelect },
251 263 props: [],
... ... @@ -256,8 +268,7 @@
256 268 isDetail: false,
257 269 isNew: false,
258 270 dataForm: {
259   - id:'',
260   - id:undefined,
  271 + id: undefined,
261 272 djrq:undefined,
262 273 cjck:undefined,
263 274 jsr:undefined,
... ... @@ -278,7 +289,6 @@
278 289 gysOptions: [],
279 290 cjckOptions : [],
280 291 rkckOptions : [],
281   - rkckOptions : [],
282 292 ckckOptions : [],
283 293 spbhOptions : [],
284 294 skzhOptions : [],
... ... @@ -300,7 +310,6 @@
300 310 console.log('created钩子执行,准备加载商品下拉');
301 311 this.getcjckOptions();
302 312 this.getrkckOptions();
303   - this.getrkckOptions();
304 313 this.getckckOptions();
305 314 this.getspbhOptions();
306 315 this.getskzhOptions();
... ... @@ -326,11 +335,6 @@
326 335 this.rkckOptions = res.data
327 336 });
328 337 },
329   - getrkckOptions(){
330   - previewDataInterface('681758216954053893').then(res => {
331   - this.rkckOptions = res.data
332   - });
333   - },
334 338 getckckOptions(){
335 339 previewDataInterface('681758216954053893').then(res => {
336 340 this.ckckOptions = res.data
... ... @@ -343,9 +347,16 @@
343 347 });
344 348 },
345 349 getskzhOptions(){
346   - getDictionaryDataSelector('681761709836207365').then(res => {
347   - this.skzhOptions = res.data.list
348   - });
  350 + return getAccountSelector()
  351 + .then(res => {
  352 + const raw = res && res.data
  353 + let list = raw && raw.list != null ? raw.list : null
  354 + if (list == null && Array.isArray(raw)) list = raw
  355 + this.skzhOptions = Array.isArray(list) ? list : []
  356 + })
  357 + .catch(() => {
  358 + this.skzhOptions = []
  359 + })
349 360 },
350 361 getgysOptions() {
351 362 return request({
... ... @@ -419,10 +430,12 @@
419 430 this.visible = true;
420 431 this.isDetail = isDetail || false;
421 432 this.currentSerialRowIndex = -1;
422   - this.$nextTick(() => {
423   - this.$refs['elForm'].resetFields();
424   - if (this.dataForm.id) {
425   - request({
  433 + this.$nextTick(async () => {
  434 + if (this.$refs['elForm']) this.$refs['elForm'].resetFields();
  435 + // 弹窗打开后再拉一次账户,避免 v-if 首屏竞态导致 skzhOptions 为空或 undefined
  436 + await this.getskzhOptions();
  437 + if (this.dataForm.id) {
  438 + request({
426 439 url: '/api/Extend/WtXsckd/' + this.dataForm.id,
427 440 method: 'get'
428 441 }).then(res =>{
... ... @@ -462,7 +475,7 @@
462 475 this.updateTotalAmount();
463 476 this.reloadInboundOrdersForExistingRows();
464 477 })
465   - } else {
  478 + } else {
466 479 this.dataForm.wtXsckdMxList = [];
467 480 // 预生成单据编号
468 481 request({
... ... @@ -474,7 +487,7 @@
474 487 this.dataForm.id = res.data.billNo;
475 488 }
476 489 }).catch(() => {});
477   - }
  490 + }
478 491 })
479 492 },
480 493 dataFormSubmit() {
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCgthd/detail-view.vue
... ... @@ -184,9 +184,9 @@
184 184  
185 185 <script>
186 186 import request from '@/utils/request'
187   -import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
188 187 import { previewDataInterface } from '@/api/systemData/dataInterface'
189 188 import { dynamicText } from '@/filters'
  189 +import { getAccountSelector } from '@/api/extend/wtAccount'
190 190  
191 191 export default {
192 192 name: 'WtCgthdDetailView',
... ... @@ -291,7 +291,7 @@ export default {
291 291 previewDataInterface('681758216954053893').then(res => {
292 292 this.ckckOptions = res.data || []
293 293 })
294   - getDictionaryDataSelector('681761709836207365').then(res => {
  294 + getAccountSelector().then(res => {
295 295 this.skzhOptions = res.data.list || []
296 296 })
297 297 }
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCgthd/index.vue
... ... @@ -146,11 +146,11 @@
146 146 </template>
147 147 <script>
148 148 import request from '@/utils/request'
149   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
150 149 import NCCForm from './Form'
151 150 import DetailView from './detail-view'
152 151 import ExportBox from './ExportBox'
153 152 import { previewDataInterface } from '@/api/systemData/dataInterface'
  153 + import { getAccountSelector } from '@/api/extend/wtAccount'
154 154 export default {
155 155 components: { NCCForm, DetailView, ExportBox },
156 156 data() {
... ... @@ -225,7 +225,7 @@
225 225 });
226 226 },
227 227 getskzhOptions(){
228   - getDictionaryDataSelector('681761709836207365').then(res => {
  228 + getAccountSelector().then(res => {
229 229 this.skzhOptions = res.data.list
230 230 });
231 231 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj/Form.vue
... ... @@ -121,6 +121,7 @@
121 121 import request from '@/utils/request'
122 122 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
123 123 import { previewDataInterface } from '@/api/systemData/dataInterface'
  124 + import { getAccountSelector } from '@/api/extend/wtAccount'
124 125 export default {
125 126 components: {},
126 127 props: [],
... ... @@ -181,17 +182,17 @@
181 182 });
182 183 },
183 184 getzhbhOptions(){
184   - getDictionaryDataSelector('681761709836207365').then(res => {
  185 + getAccountSelector().then(res => {
185 186 this.zhbhOptions = res.data.list
186 187 });
187 188 },
188 189 getfkzhOptions(){
189   - getDictionaryDataSelector('681761709836207365').then(res => {
  190 + getAccountSelector().then(res => {
190 191 this.fkzhOptions = res.data.list
191 192 });
192 193 },
193 194 getskzhOptions(){
194   - getDictionaryDataSelector('681761709836207365').then(res => {
  195 + getAccountSelector().then(res => {
195 196 this.skzhOptions = res.data.list
196 197 });
197 198 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj/index.vue
... ... @@ -85,10 +85,10 @@
85 85 </template>
86 86 <script>
87 87 import request from '@/utils/request'
88   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
89 88 import NCCForm from './Form'
90 89 import ExportBox from './ExportBox'
91 90 import { previewDataInterface } from '@/api/systemData/dataInterface'
  91 + import { getAccountSelector } from '@/api/extend/wtAccount'
92 92 export default {
93 93 components: { NCCForm, ExportBox },
94 94 data() {
... ... @@ -138,12 +138,12 @@
138 138 });
139 139 },
140 140 getfkzhOptions(){
141   - getDictionaryDataSelector('681761709836207365').then(res => {
  141 + getAccountSelector().then(res => {
142 142 this.fkzhOptions = res.data.list
143 143 });
144 144 },
145 145 getskzhOptions(){
146   - getDictionaryDataSelector('681761709836207365').then(res => {
  146 + getAccountSelector().then(res => {
147 147 this.skzhOptions = res.data.list
148 148 });
149 149 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_dtfyfs/Form.vue
... ... @@ -127,6 +127,7 @@
127 127 import request from '@/utils/request'
128 128 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
129 129 import { previewDataInterface } from '@/api/systemData/dataInterface'
  130 + import { getAccountSelector } from '@/api/extend/wtAccount'
130 131 export default {
131 132 components: {},
132 133 props: [],
... ... @@ -193,17 +194,17 @@
193 194 });
194 195 },
195 196 getzhbhOptions(){
196   - getDictionaryDataSelector('681761709836207365').then(res => {
  197 + getAccountSelector().then(res => {
197 198 this.zhbhOptions = res.data.list
198 199 });
199 200 },
200 201 getfkzhOptions(){
201   - getDictionaryDataSelector('681761709836207365').then(res => {
  202 + getAccountSelector().then(res => {
202 203 this.fkzhOptions = res.data.list
203 204 });
204 205 },
205 206 getskzhOptions(){
206   - getDictionaryDataSelector('681761709836207365').then(res => {
  207 + getAccountSelector().then(res => {
207 208 this.skzhOptions = res.data.list
208 209 });
209 210 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_dtfyfs/index.vue
... ... @@ -90,10 +90,10 @@
90 90 </template>
91 91 <script>
92 92 import request from '@/utils/request'
93   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
94 93 import NCCForm from './Form'
95 94 import ExportBox from './ExportBox'
96 95 import { previewDataInterface } from '@/api/systemData/dataInterface'
  96 + import { getAccountSelector } from '@/api/extend/wtAccount'
97 97 export default {
98 98 components: { NCCForm, ExportBox },
99 99 data() {
... ... @@ -145,12 +145,12 @@
145 145 });
146 146 },
147 147 getfkzhOptions(){
148   - getDictionaryDataSelector('681761709836207365').then(res => {
  148 + getAccountSelector().then(res => {
149 149 this.fkzhOptions = res.data.list
150 150 });
151 151 },
152 152 getskzhOptions(){
153   - getDictionaryDataSelector('681761709836207365').then(res => {
  153 + getAccountSelector().then(res => {
154 154 this.skzhOptions = res.data.list
155 155 });
156 156 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_dtfytx/Form.vue
... ... @@ -121,6 +121,7 @@
121 121 import request from '@/utils/request'
122 122 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
123 123 import { previewDataInterface } from '@/api/systemData/dataInterface'
  124 + import { getAccountSelector } from '@/api/extend/wtAccount'
124 125 export default {
125 126 components: {},
126 127 props: [],
... ... @@ -182,17 +183,17 @@
182 183 });
183 184 },
184 185 getzhbhOptions(){
185   - getDictionaryDataSelector('681761709836207365').then(res => {
  186 + getAccountSelector().then(res => {
186 187 this.zhbhOptions = res.data.list
187 188 });
188 189 },
189 190 getfkzhOptions(){
190   - getDictionaryDataSelector('681761709836207365').then(res => {
  191 + getAccountSelector().then(res => {
191 192 this.fkzhOptions = res.data.list
192 193 });
193 194 },
194 195 getskzhOptions(){
195   - getDictionaryDataSelector('681761709836207365').then(res => {
  196 + getAccountSelector().then(res => {
196 197 this.skzhOptions = res.data.list
197 198 });
198 199 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_dtfytx/index.vue
... ... @@ -89,10 +89,10 @@
89 89 </template>
90 90 <script>
91 91 import request from '@/utils/request'
92   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
93 92 import NCCForm from './Form'
94 93 import ExportBox from './ExportBox'
95 94 import { previewDataInterface } from '@/api/systemData/dataInterface'
  95 + import { getAccountSelector } from '@/api/extend/wtAccount'
96 96 export default {
97 97 components: { NCCForm, ExportBox },
98 98 data() {
... ... @@ -142,12 +142,12 @@
142 142 });
143 143 },
144 144 getfkzhOptions(){
145   - getDictionaryDataSelector('681761709836207365').then(res => {
  145 + getAccountSelector().then(res => {
146 146 this.fkzhOptions = res.data.list
147 147 });
148 148 },
149 149 getskzhOptions(){
150   - getDictionaryDataSelector('681761709836207365').then(res => {
  150 + getAccountSelector().then(res => {
151 151 this.skzhOptions = res.data.list
152 152 });
153 153 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_fkd/Form.vue
... ... @@ -128,6 +128,7 @@
128 128 import request from '@/utils/request'
129 129 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
130 130 import { previewDataInterface } from '@/api/systemData/dataInterface'
  131 + import { getAccountSelector } from '@/api/extend/wtAccount'
131 132 export default {
132 133 components: {},
133 134 props: [],
... ... @@ -190,17 +191,17 @@
190 191 });
191 192 },
192 193 getzhbhOptions(){
193   - getDictionaryDataSelector('681761709836207365').then(res => {
  194 + getAccountSelector().then(res => {
194 195 this.zhbhOptions = res.data.list
195 196 });
196 197 },
197 198 getfkzhOptions(){
198   - getDictionaryDataSelector('681761709836207365').then(res => {
  199 + getAccountSelector().then(res => {
199 200 this.fkzhOptions = res.data.list
200 201 });
201 202 },
202 203 getskzhOptions(){
203   - getDictionaryDataSelector('681761709836207365').then(res => {
  204 + getAccountSelector().then(res => {
204 205 this.skzhOptions = res.data.list
205 206 });
206 207 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_fkd/detail-view.vue
... ... @@ -124,6 +124,7 @@ import request from &#39;@/utils/request&#39;
124 124 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
125 125 import { previewDataInterface } from '@/api/systemData/dataInterface'
126 126 import { dynamicText } from '@/filters'
  127 +import { getAccountSelector } from '@/api/extend/wtAccount'
127 128  
128 129 export default {
129 130 name: 'WtCwdjFkdDetailView',
... ... @@ -216,7 +217,7 @@ export default {
216 217 previewDataInterface('716168694526379269').then(res => {
217 218 this.wldwOptions = res.data || []
218 219 })
219   - getDictionaryDataSelector('681761709836207365').then(res => {
  220 + getAccountSelector().then(res => {
220 221 this.zhbhOptions = res.data.list || []
221 222 })
222 223 getDictionaryDataSelector('715562947862070533').then(res => {
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_fkd/index.vue
... ... @@ -91,11 +91,11 @@
91 91 </template>
92 92 <script>
93 93 import request from '@/utils/request'
94   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
95 94 import NCCForm from './Form'
96 95 import DetailView from './detail-view'
97 96 import ExportBox from './ExportBox'
98 97 import { previewDataInterface } from '@/api/systemData/dataInterface'
  98 + import { getAccountSelector } from '@/api/extend/wtAccount'
99 99 export default {
100 100 components: { NCCForm, DetailView, ExportBox },
101 101 data() {
... ... @@ -146,12 +146,12 @@
146 146 });
147 147 },
148 148 getfkzhOptions(){
149   - getDictionaryDataSelector('681761709836207365').then(res => {
  149 + getAccountSelector().then(res => {
150 150 this.fkzhOptions = res.data.list
151 151 });
152 152 },
153 153 getskzhOptions(){
154   - getDictionaryDataSelector('681761709836207365').then(res => {
  154 + getAccountSelector().then(res => {
155 155 this.skzhOptions = res.data.list
156 156 });
157 157 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_fyd/Form.vue
... ... @@ -134,6 +134,7 @@
134 134 import request from '@/utils/request'
135 135 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
136 136 import { previewDataInterface } from '@/api/systemData/dataInterface'
  137 + import { getAccountSelector } from '@/api/extend/wtAccount'
137 138 export default {
138 139 components: {},
139 140 props: [],
... ... @@ -195,17 +196,17 @@
195 196 });
196 197 },
197 198 getzhbhOptions(){
198   - getDictionaryDataSelector('681761709836207365').then(res => {
  199 + getAccountSelector().then(res => {
199 200 this.zhbhOptions = res.data.list
200 201 });
201 202 },
202 203 getfkzhOptions(){
203   - getDictionaryDataSelector('681761709836207365').then(res => {
  204 + getAccountSelector().then(res => {
204 205 this.fkzhOptions = res.data.list
205 206 });
206 207 },
207 208 getskzhOptions(){
208   - getDictionaryDataSelector('681761709836207365').then(res => {
  209 + getAccountSelector().then(res => {
209 210 this.skzhOptions = res.data.list
210 211 });
211 212 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_fyd/index.vue
... ... @@ -107,10 +107,10 @@
107 107 </template>
108 108 <script>
109 109 import request from '@/utils/request'
110   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
111 110 import NCCForm from './Form'
112 111 import ExportBox from './ExportBox'
113 112 import { previewDataInterface } from '@/api/systemData/dataInterface'
  113 + import { getAccountSelector } from '@/api/extend/wtAccount'
114 114 export default {
115 115 components: { NCCForm, ExportBox },
116 116 data() {
... ... @@ -162,12 +162,12 @@
162 162 });
163 163 },
164 164 getfkzhOptions(){
165   - getDictionaryDataSelector('681761709836207365').then(res => {
  165 + getAccountSelector().then(res => {
166 166 this.fkzhOptions = res.data.list
167 167 });
168 168 },
169 169 getskzhOptions(){
170   - getDictionaryDataSelector('681761709836207365').then(res => {
  170 + getAccountSelector().then(res => {
171 171 this.skzhOptions = res.data.list
172 172 });
173 173 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_gdzcbm/Form.vue
... ... @@ -121,6 +121,7 @@
121 121 import request from '@/utils/request'
122 122 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
123 123 import { previewDataInterface } from '@/api/systemData/dataInterface'
  124 + import { getAccountSelector } from '@/api/extend/wtAccount'
124 125 export default {
125 126 components: {},
126 127 props: [],
... ... @@ -182,17 +183,17 @@
182 183 });
183 184 },
184 185 getzhbhOptions(){
185   - getDictionaryDataSelector('681761709836207365').then(res => {
  186 + getAccountSelector().then(res => {
186 187 this.zhbhOptions = res.data.list
187 188 });
188 189 },
189 190 getfkzhOptions(){
190   - getDictionaryDataSelector('681761709836207365').then(res => {
  191 + getAccountSelector().then(res => {
191 192 this.fkzhOptions = res.data.list
192 193 });
193 194 },
194 195 getskzhOptions(){
195   - getDictionaryDataSelector('681761709836207365').then(res => {
  196 + getAccountSelector().then(res => {
196 197 this.skzhOptions = res.data.list
197 198 });
198 199 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_gdzcbm/index.vue
... ... @@ -89,10 +89,10 @@
89 89 </template>
90 90 <script>
91 91 import request from '@/utils/request'
92   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
93 92 import NCCForm from './Form'
94 93 import ExportBox from './ExportBox'
95 94 import { previewDataInterface } from '@/api/systemData/dataInterface'
  95 + import { getAccountSelector } from '@/api/extend/wtAccount'
96 96 export default {
97 97 components: { NCCForm, ExportBox },
98 98 data() {
... ... @@ -142,12 +142,12 @@
142 142 });
143 143 },
144 144 getfkzhOptions(){
145   - getDictionaryDataSelector('681761709836207365').then(res => {
  145 + getAccountSelector().then(res => {
146 146 this.fkzhOptions = res.data.list
147 147 });
148 148 },
149 149 getskzhOptions(){
150   - getDictionaryDataSelector('681761709836207365').then(res => {
  150 + getAccountSelector().then(res => {
151 151 this.skzhOptions = res.data.list
152 152 });
153 153 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_gdzcgm/Form.vue
... ... @@ -127,6 +127,7 @@
127 127 import request from '@/utils/request'
128 128 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
129 129 import { previewDataInterface } from '@/api/systemData/dataInterface'
  130 + import { getAccountSelector } from '@/api/extend/wtAccount'
130 131 export default {
131 132 components: {},
132 133 props: [],
... ... @@ -193,17 +194,17 @@
193 194 });
194 195 },
195 196 getzhbhOptions(){
196   - getDictionaryDataSelector('681761709836207365').then(res => {
  197 + getAccountSelector().then(res => {
197 198 this.zhbhOptions = res.data.list
198 199 });
199 200 },
200 201 getfkzhOptions(){
201   - getDictionaryDataSelector('681761709836207365').then(res => {
  202 + getAccountSelector().then(res => {
202 203 this.fkzhOptions = res.data.list
203 204 });
204 205 },
205 206 getskzhOptions(){
206   - getDictionaryDataSelector('681761709836207365').then(res => {
  207 + getAccountSelector().then(res => {
207 208 this.skzhOptions = res.data.list
208 209 });
209 210 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_gdzcgm/index.vue
... ... @@ -90,10 +90,10 @@
90 90 </template>
91 91 <script>
92 92 import request from '@/utils/request'
93   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
94 93 import NCCForm from './Form'
95 94 import ExportBox from './ExportBox'
96 95 import { previewDataInterface } from '@/api/systemData/dataInterface'
  96 + import { getAccountSelector } from '@/api/extend/wtAccount'
97 97 export default {
98 98 components: { NCCForm, ExportBox },
99 99 data() {
... ... @@ -145,12 +145,12 @@
145 145 });
146 146 },
147 147 getfkzhOptions(){
148   - getDictionaryDataSelector('681761709836207365').then(res => {
  148 + getAccountSelector().then(res => {
149 149 this.fkzhOptions = res.data.list
150 150 });
151 151 },
152 152 getskzhOptions(){
153   - getDictionaryDataSelector('681761709836207365').then(res => {
  153 + getAccountSelector().then(res => {
154 154 this.skzhOptions = res.data.list
155 155 });
156 156 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_gdzczj/Form.vue
... ... @@ -121,6 +121,7 @@
121 121 import request from '@/utils/request'
122 122 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
123 123 import { previewDataInterface } from '@/api/systemData/dataInterface'
  124 + import { getAccountSelector } from '@/api/extend/wtAccount'
124 125 export default {
125 126 components: {},
126 127 props: [],
... ... @@ -182,17 +183,17 @@
182 183 });
183 184 },
184 185 getzhbhOptions(){
185   - getDictionaryDataSelector('681761709836207365').then(res => {
  186 + getAccountSelector().then(res => {
186 187 this.zhbhOptions = res.data.list
187 188 });
188 189 },
189 190 getfkzhOptions(){
190   - getDictionaryDataSelector('681761709836207365').then(res => {
  191 + getAccountSelector().then(res => {
191 192 this.fkzhOptions = res.data.list
192 193 });
193 194 },
194 195 getskzhOptions(){
195   - getDictionaryDataSelector('681761709836207365').then(res => {
  196 + getAccountSelector().then(res => {
196 197 this.skzhOptions = res.data.list
197 198 });
198 199 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_gdzczj/index.vue
... ... @@ -89,10 +89,10 @@
89 89 </template>
90 90 <script>
91 91 import request from '@/utils/request'
92   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
93 92 import NCCForm from './Form'
94 93 import ExportBox from './ExportBox'
95 94 import { previewDataInterface } from '@/api/systemData/dataInterface'
  95 + import { getAccountSelector } from '@/api/extend/wtAccount'
96 96 export default {
97 97 components: { NCCForm, ExportBox },
98 98 data() {
... ... @@ -142,12 +142,12 @@
142 142 });
143 143 },
144 144 getfkzhOptions(){
145   - getDictionaryDataSelector('681761709836207365').then(res => {
  145 + getAccountSelector().then(res => {
146 146 this.fkzhOptions = res.data.list
147 147 });
148 148 },
149 149 getskzhOptions(){
150   - getDictionaryDataSelector('681761709836207365').then(res => {
  150 + getAccountSelector().then(res => {
151 151 this.skzhOptions = res.data.list
152 152 });
153 153 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_skd/Form.vue
... ... @@ -128,6 +128,7 @@
128 128 import request from '@/utils/request'
129 129 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
130 130 import { previewDataInterface } from '@/api/systemData/dataInterface'
  131 + import { getAccountSelector } from '@/api/extend/wtAccount'
131 132 export default {
132 133 components: {},
133 134 props: [],
... ... @@ -190,17 +191,17 @@
190 191 });
191 192 },
192 193 getzhbhOptions(){
193   - getDictionaryDataSelector('681761709836207365').then(res => {
  194 + getAccountSelector().then(res => {
194 195 this.zhbhOptions = res.data.list
195 196 });
196 197 },
197 198 getfkzhOptions(){
198   - getDictionaryDataSelector('681761709836207365').then(res => {
  199 + getAccountSelector().then(res => {
199 200 this.fkzhOptions = res.data.list
200 201 });
201 202 },
202 203 getskzhOptions(){
203   - getDictionaryDataSelector('681761709836207365').then(res => {
  204 + getAccountSelector().then(res => {
204 205 this.skzhOptions = res.data.list
205 206 });
206 207 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_skd/detail-view.vue
... ... @@ -124,6 +124,7 @@ import request from &#39;@/utils/request&#39;
124 124 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
125 125 import { previewDataInterface } from '@/api/systemData/dataInterface'
126 126 import { dynamicText } from '@/filters'
  127 +import { getAccountSelector } from '@/api/extend/wtAccount'
127 128  
128 129 export default {
129 130 name: 'WtCwdjSkdDetailView',
... ... @@ -216,7 +217,7 @@ export default {
216 217 previewDataInterface('716168694526379269').then(res => {
217 218 this.wldwOptions = res.data || []
218 219 })
219   - getDictionaryDataSelector('681761709836207365').then(res => {
  220 + getAccountSelector().then(res => {
220 221 this.zhbhOptions = res.data.list || []
221 222 })
222 223 getDictionaryDataSelector('715562947862070533').then(res => {
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_skd/index.vue
... ... @@ -91,11 +91,11 @@
91 91 </template>
92 92 <script>
93 93 import request from '@/utils/request'
94   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
95 94 import NCCForm from './Form'
96 95 import DetailView from './detail-view'
97 96 import ExportBox from './ExportBox'
98 97 import { previewDataInterface } from '@/api/systemData/dataInterface'
  98 + import { getAccountSelector } from '@/api/extend/wtAccount'
99 99 export default {
100 100 components: { NCCForm, DetailView, ExportBox },
101 101 data() {
... ... @@ -146,12 +146,12 @@
146 146 });
147 147 },
148 148 getfkzhOptions(){
149   - getDictionaryDataSelector('681761709836207365').then(res => {
  149 + getAccountSelector().then(res => {
150 150 this.fkzhOptions = res.data.list
151 151 });
152 152 },
153 153 getskzhOptions(){
154   - getDictionaryDataSelector('681761709836207365').then(res => {
  154 + getAccountSelector().then(res => {
155 155 this.skzhOptions = res.data.list
156 156 });
157 157 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtFkd/Form.vue
... ... @@ -86,8 +86,8 @@
86 86 </template>
87 87 <script>
88 88 import request from '@/utils/request'
89   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
90 89 import { previewDataInterface } from '@/api/systemData/dataInterface'
  90 + import { getAccountSelector } from '@/api/extend/wtAccount'
91 91 export default {
92 92 components: {},
93 93 props: [],
... ... @@ -132,7 +132,7 @@
132 132 });
133 133 },
134 134 getjszhOptions(){
135   - getDictionaryDataSelector('681761709836207365').then(res => {
  135 + getAccountSelector().then(res => {
136 136 this.jszhOptions = res.data.list
137 137 });
138 138 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtFkd/index.vue
... ... @@ -121,10 +121,10 @@
121 121 </template>
122 122 <script>
123 123 import request from '@/utils/request'
124   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
125 124 import NCCForm from './Form'
126 125 import ExportBox from './ExportBox'
127 126 import { previewDataInterface } from '@/api/systemData/dataInterface'
  127 + import { getAccountSelector } from '@/api/extend/wtAccount'
128 128 export default {
129 129 components: { NCCForm, ExportBox },
130 130 data() {
... ... @@ -184,7 +184,7 @@
184 184 });
185 185 },
186 186 getjszhOptions(){
187   - getDictionaryDataSelector('681761709836207365').then(res => {
  187 + getAccountSelector().then(res => {
188 188 this.jszhOptions = res.data.list
189 189 });
190 190 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtHzd/Form.vue
... ... @@ -287,10 +287,10 @@
287 287 </template>
288 288 <script>
289 289 import request from '@/utils/request'
290   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
291 290 import { previewDataInterface } from '@/api/systemData/dataInterface'
292 291 import BarcodeSelect from '../wtCgrkd/BarcodeSelect.vue'
293 292 import SerialNumberSelect from './SerialNumberSelect.vue'
  293 + import { getAccountSelector } from '@/api/extend/wtAccount'
294 294 export default {
295 295 components: { BarcodeSelect, SerialNumberSelect },
296 296 props: [],
... ... @@ -607,7 +607,7 @@
607 607 });
608 608 },
609 609 getskzhOptions(){
610   - getDictionaryDataSelector('681761709836207365').then(res => {
  610 + getAccountSelector().then(res => {
611 611 this.skzhOptions = res.data.list
612 612 });
613 613 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtHzd/index.vue
... ... @@ -144,10 +144,10 @@
144 144 </template>
145 145 <script>
146 146 import request from '@/utils/request'
147   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
148 147 import NCCForm from './Form'
149 148 import ExportBox from './ExportBox'
150 149 import { previewDataInterface } from '@/api/systemData/dataInterface'
  150 + import { getAccountSelector } from '@/api/extend/wtAccount'
151 151 export default {
152 152 components: { NCCForm, ExportBox },
153 153 data() {
... ... @@ -218,7 +218,7 @@
218 218 });
219 219 },
220 220 getskzhOptions(){
221   - getDictionaryDataSelector('681761709836207365').then(res => {
  221 + getAccountSelector().then(res => {
222 222 this.skzhOptions = res.data.list
223 223 });
224 224 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtMrsz/index.vue
... ... @@ -32,8 +32,8 @@
32 32  
33 33 <script>
34 34 import request from '@/utils/request'
35   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
36 35 import { previewDataInterface } from '@/api/systemData/dataInterface'
  36 + import { getAccountSelector } from '@/api/extend/wtAccount'
37 37  
38 38 export default {
39 39 name: 'wtMrsz',
... ... @@ -72,7 +72,7 @@
72 72 }).catch(() => {})
73 73  
74 74 // 收款账户(字典数据,与销售出库单一致)
75   - getDictionaryDataSelector('681761709836207365').then(res => {
  75 + getAccountSelector().then(res => {
76 76 this.skzhOptions = res.data && res.data.list ? res.data.list : []
77 77 }).catch(() => {})
78 78 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtPdd/Form.vue
... ... @@ -282,10 +282,10 @@
282 282 </template>
283 283 <script>
284 284 import request from '@/utils/request'
285   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
286 285 import { previewDataInterface } from '@/api/systemData/dataInterface'
287 286 import BarcodeSelect from '../wtCgrkd/BarcodeSelect.vue'
288 287 import SerialNumberSelect from './SerialNumberSelect.vue'
  288 + import { getAccountSelector } from '@/api/extend/wtAccount'
289 289 export default {
290 290 components: { BarcodeSelect, SerialNumberSelect },
291 291 props: [],
... ... @@ -606,7 +606,7 @@
606 606 });
607 607 },
608 608 getskzhOptions(){
609   - getDictionaryDataSelector('681761709836207365').then(res => {
  609 + getAccountSelector().then(res => {
610 610 this.skzhOptions = res.data.list
611 611 });
612 612 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtPdd/index.vue
... ... @@ -144,10 +144,10 @@
144 144 </template>
145 145 <script>
146 146 import request from '@/utils/request'
147   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
148 147 import NCCForm from './Form'
149 148 import ExportBox from './ExportBox'
150 149 import { previewDataInterface } from '@/api/systemData/dataInterface'
  150 + import { getAccountSelector } from '@/api/extend/wtAccount'
151 151 export default {
152 152 components: { NCCForm, ExportBox },
153 153 data() {
... ... @@ -218,7 +218,7 @@
218 218 });
219 219 },
220 220 getskzhOptions(){
221   - getDictionaryDataSelector('681761709836207365').then(res => {
  221 + getAccountSelector().then(res => {
222 222 this.skzhOptions = res.data.list
223 223 });
224 224 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtPurchaseSummary/index.vue
1 1 <template>
2   - <div class="purchase-summary-page">
3   - <div class="form-section">
4   - <el-form :inline="false" :model="filters" label-width="90px" size="small">
5   - <el-row :gutter="10">
6   - <el-col :span="12">
  2 + <div class="NCC-common-layout">
  3 + <div class="NCC-common-layout-center">
  4 + <el-row class="NCC-common-search-box" :gutter="16">
  5 + <el-form @submit.native.prevent>
  6 + <el-col :span="6">
7 7 <el-form-item label="查询日期">
8 8 <el-date-picker
9 9 v-model="filters.dateRange"
... ... @@ -13,10 +13,11 @@
13 13 end-placeholder="结束日期"
14 14 style="width: 100%"
15 15 value-format="yyyy-MM-dd"
  16 + clearable
16 17 />
17 18 </el-form-item>
18 19 </el-col>
19   - <el-col :span="12">
  20 + <el-col :span="6">
20 21 <el-form-item label="往来单位">
21 22 <el-select
22 23 v-model="filters.contactUnit"
... ... @@ -36,8 +37,8 @@
36 37 </el-select>
37 38 </el-form-item>
38 39 </el-col>
39   - <el-col :span="12">
40   - <el-form-item label="经 手 人">
  40 + <el-col :span="6">
  41 + <el-form-item label="经手人">
41 42 <el-select
42 43 v-model="filters.agent"
43 44 multiple
... ... @@ -49,36 +50,43 @@
49 50 >
50 51 <el-option
51 52 v-for="item in agentOptions"
52   - :key="item"
53   - :label="item"
54   - :value="item"
  53 + :key="item.value"
  54 + :label="item.label"
  55 + :value="item.value"
55 56 />
56 57 </el-select>
57 58 </el-form-item>
58 59 </el-col>
59   - <el-col :span="12">
  60 + <el-col :span="6">
60 61 <el-form-item label="商品">
61 62 <el-select
62   - v-model="filters.productName"
  63 + v-model="filters.productSpId"
63 64 filterable
64 65 remote
65 66 clearable
66 67 reserve-keyword
  68 + popper-class="wt-purchase-sum-product-dropdown"
67 69 :remote-method="handleProductSearch"
68 70 :loading="productLoading"
69   - placeholder="请输入商品编号或名称搜索"
  71 + placeholder="输入商品编码或名称搜索"
70 72 style="width: 100%"
71 73 >
72 74 <el-option
73 75 v-for="item in productOptions"
74   - :key="item.F_Id || item.id || item.spbm || item.productCode"
  76 + :key="item.F_Id || item.id"
75 77 :label="formatProductLabel(item)"
76   - :value="formatProductLabel(item)"
77   - />
  78 + :value="item.F_Id || item.id"
  79 + >
  80 + <div class="product-opt-row cell-nowrap" :title="formatProductLabel(item)">
  81 + <span v-if="productCodeRaw(item)" class="product-opt-code">{{ productCodeRaw(item) }}</span>
  82 + <span v-if="productCodeRaw(item) && productNameRaw(item)" class="product-opt-sep">|</span>
  83 + <span class="product-opt-name">{{ productNameRaw(item) || '无' }}</span>
  84 + </div>
  85 + </el-option>
78 86 </el-select>
79 87 </el-form-item>
80 88 </el-col>
81   - <el-col :span="12">
  89 + <el-col :span="6">
82 90 <el-form-item label="入库仓库">
83 91 <el-select
84 92 v-model="filters.warehouse"
... ... @@ -98,7 +106,7 @@
98 106 </el-select>
99 107 </el-form-item>
100 108 </el-col>
101   - <el-col :span="12">
  109 + <el-col :span="6">
102 110 <el-form-item label="单据类型">
103 111 <el-select
104 112 v-model="filters.billType"
... ... @@ -106,7 +114,7 @@
106 114 collapse-tags
107 115 clearable
108 116 style="width: 100%"
109   - placeholder="全部单据"
  117 + placeholder="全部相关单据"
110 118 >
111 119 <el-option
112 120 v-for="item in billTypeOptions"
... ... @@ -117,65 +125,220 @@
117 125 </el-select>
118 126 </el-form-item>
119 127 </el-col>
120   - <el-col :span="24">
121   - <div class="action-row">
122   - <el-button type="primary" size="mini" @click="handleSearch">搜索</el-button>
123   - <el-button size="mini" @click="handleReset">重置</el-button>
124   - </div>
  128 + <el-col :span="6">
  129 + <el-form-item>
  130 + <el-button type="primary" icon="el-icon-search" @click="handleSearch">查询</el-button>
  131 + <el-button icon="el-icon-refresh-right" @click="handleReset">重置</el-button>
  132 + </el-form-item>
125 133 </el-col>
126   - </el-row>
127   - </el-form>
128   - </div>
129   - <div class="table-section">
130   - <div class="table-title-bar">
131   - <i class="el-icon-document" style="font-size: 20px; margin-right: 6px; color: #409eff" />
132   - <span>商品采购汇总表 · 过往采购记录</span>
133   - </div>
134   - <div class="table-scroll">
  134 + </el-form>
  135 + </el-row>
  136 +
  137 + <div class="NCC-common-layout-main NCC-flex-main">
  138 + <div class="NCC-common-head purchase-sum-head">
  139 + <div>
  140 + <span class="purchase-sum-head__title">
  141 + <i class="el-icon-s-data purchase-sum-head__icon" aria-hidden="true" />
  142 + 商品采购汇总(分类 → 品牌 → 商品明细分类 → 采购明细)
  143 + </span>
  144 + </div>
  145 + <div class="NCC-common-head-right">
  146 + <el-tooltip effect="dark" content="刷新" placement="top">
  147 + <el-link
  148 + icon="icon-ym icon-ym-Refresh NCC-common-head-icon"
  149 + :underline="false"
  150 + @click="handleSearch"
  151 + />
  152 + </el-tooltip>
  153 + <screenfull isContainer />
  154 + </div>
  155 + </div>
  156 +
135 157 <el-table
136   - :data="list"
  158 + v-loading="categoryLoading"
  159 + :data="categoryList"
137 160 border
138   - style="width: 100%"
139   - :header-cell-style="{ background: '#f5f7fa' }"
140   - class="purchase-record-table"
  161 + class="purchase-tree-table"
  162 + :row-key="r => String(r['分类Id'])"
  163 + @expand-change="onCategoryExpand"
141 164 >
142   - <el-table-column type="index" label="行号" width="56" :index="indexMethod" fixed />
143   - <el-table-column prop="单据日期" label="单据日期" width="110" show-overflow-tooltip />
144   - <el-table-column prop="单据编号" label="单据编号" min-width="160" show-overflow-tooltip />
145   - <el-table-column prop="单据类型" label="单据类型" width="120" show-overflow-tooltip />
146   - <el-table-column prop="往来单位" label="往来单位" min-width="140" show-overflow-tooltip />
147   - <el-table-column prop="经手人" label="经手人" width="100" show-overflow-tooltip />
148   - <el-table-column prop="仓库名称" label="仓库名称" min-width="120" show-overflow-tooltip />
149   - <el-table-column prop="商品名称" label="商品名称" min-width="160" show-overflow-tooltip />
150   - <el-table-column prop="数量" label="数量" width="90" align="right">
151   - <template slot-scope="scope">
152   - {{ formatQty(scope.row['数量']) }}
  165 + <el-table-column type="expand" width="48">
  166 + <template slot-scope="catScope">
  167 + <div v-loading="brandLoading[categoryRowKey(catScope.row)]" class="nested-wrap">
  168 + <el-table
  169 + :data="brandMap[categoryRowKey(catScope.row)] || []"
  170 + border
  171 + size="small"
  172 + class="nested-table"
  173 + :row-key="r => brandRowKey(catScope.row, r)"
  174 + @expand-change="(r, er) => onBrandExpand(catScope.row, r, er)"
  175 + >
  176 + <el-table-column type="expand" width="44">
  177 + <template slot-scope="brandScope">
  178 + <div v-loading="productLoading[brandRowKey(catScope.row, brandScope.row)]" class="nested-wrap">
  179 + <el-table
  180 + :data="productMap[brandRowKey(catScope.row, brandScope.row)] || []"
  181 + border
  182 + size="small"
  183 + class="nested-table nested-table--deep"
  184 + :row-key="r => productRowKey(catScope.row, brandScope.row, r)"
  185 + @expand-change="(r, er) => onProductExpand(catScope.row, brandScope.row, r, er)"
  186 + >
  187 + <el-table-column type="expand" width="42">
  188 + <template slot-scope="prodScope">
  189 + <div v-loading="lineLoading[lineKey(catScope.row, brandScope.row, prodScope.row)]" class="nested-wrap detail-wrap">
  190 + <el-table
  191 + :data="(lineMap[lineKey(catScope.row, brandScope.row, prodScope.row)] || {}).list || []"
  192 + border
  193 + size="mini"
  194 + class="nested-table"
  195 + >
  196 + <el-table-column type="index" label="行号" width="52" align="center" />
  197 + <el-table-column prop="单据日期" label="单据日期" width="108" show-overflow-tooltip sortable :sort-method="sortTextCol('单据日期')" />
  198 + <el-table-column prop="单据编号" label="单据编号" min-width="140" show-overflow-tooltip sortable :sort-method="sortTextCol('单据编号')" />
  199 + <el-table-column prop="单据类型" label="单据类型" width="108" show-overflow-tooltip sortable :sort-method="sortTextCol('单据类型')" />
  200 + <el-table-column prop="往来单位" label="往来单位" min-width="120" show-overflow-tooltip sortable :sort-method="sortTextCol('往来单位')" />
  201 + <el-table-column prop="经手人" label="经手人" width="88" show-overflow-tooltip sortable :sort-method="sortTextCol('经手人')" />
  202 + <el-table-column prop="仓库名称" label="仓库名称" min-width="100" show-overflow-tooltip sortable :sort-method="sortTextCol('仓库名称')" />
  203 + <el-table-column prop="商品名称" label="商品名称" min-width="140" show-overflow-tooltip sortable :sort-method="sortTextCol('商品名称')" />
  204 + <el-table-column prop="数量" label="数量" width="88" align="right" sortable :sort-method="sortNumCol('数量')">
  205 + <template slot-scope="s">{{ formatQty(s.row['数量']) }}</template>
  206 + </el-table-column>
  207 + <el-table-column prop="入库单价" label="入库单价" width="100" align="right" sortable :sort-method="sortNumCol('入库单价')">
  208 + <template slot-scope="s">{{ formatMoney(s.row['入库单价']) }}</template>
  209 + </el-table-column>
  210 + <el-table-column prop="采购金额" label="采购金额" width="108" align="right" sortable :sort-method="sortNumCol('采购金额')">
  211 + <template slot-scope="s">{{ formatMoney(s.row['采购金额']) }}</template>
  212 + </el-table-column>
  213 + </el-table>
  214 + <div v-if="linePager[lineKey(catScope.row, brandScope.row, prodScope.row)]" class="mini-pager">
  215 + <el-pagination
  216 + small
  217 + layout="prev, pager, next, total"
  218 + :total="linePager[lineKey(catScope.row, brandScope.row, prodScope.row)].total"
  219 + :page-size="linePager[lineKey(catScope.row, brandScope.row, prodScope.row)].pageSize"
  220 + :current-page="linePager[lineKey(catScope.row, brandScope.row, prodScope.row)].currentPage"
  221 + @current-change="p => fetchLines(catScope.row, brandScope.row, prodScope.row, p)"
  222 + />
  223 + </div>
  224 + </div>
  225 + </template>
  226 + </el-table-column>
  227 + <el-table-column label="商品编号" min-width="100" show-overflow-tooltip sortable :sort-method="sortTextCol('商品编号')">
  228 + <template slot-scope="s">
  229 + <i class="el-icon-postcard row-ico row-ico--primary" />
  230 + {{ cellText(s.row['商品编号']) }}
  231 + </template>
  232 + </el-table-column>
  233 + <el-table-column label="明细分类" min-width="120" show-overflow-tooltip sortable :sort-method="sortTextCol('明细分类')">
  234 + <template slot-scope="s">
  235 + <i class="el-icon-collection-tag row-ico row-ico--info" />
  236 + {{ cellText(s.row['明细分类']) }}
  237 + </template>
  238 + </el-table-column>
  239 + <el-table-column label="商品名称" min-width="140" show-overflow-tooltip sortable :sort-method="sortTextCol('商品名称')">
  240 + <template slot-scope="s">
  241 + <i class="el-icon-goods row-ico row-ico--muted" />
  242 + {{ cellText(s.row['商品名称']) }}
  243 + </template>
  244 + </el-table-column>
  245 + <el-table-column label="数量" width="88" align="right" sortable :sort-method="sortNumCol('数量')">
  246 + <template slot-scope="s">{{ formatQty(s.row['数量']) }}</template>
  247 + </el-table-column>
  248 + <el-table-column label="入库单价" width="100" align="right" sortable :sort-method="sortNumCol('入库单价')">
  249 + <template slot-scope="s">{{ formatMoney(s.row['入库单价']) }}</template>
  250 + </el-table-column>
  251 + <el-table-column label="采购金额" width="108" align="right" sortable :sort-method="sortNumCol('采购金额')">
  252 + <template slot-scope="s">{{ formatMoney(s.row['采购金额']) }}</template>
  253 + </el-table-column>
  254 + </el-table>
  255 + </div>
  256 + </template>
  257 + </el-table-column>
  258 + <el-table-column label="品牌" min-width="140" show-overflow-tooltip sortable :sort-method="sortTextCol('品牌名称')">
  259 + <template slot-scope="s">
  260 + <i class="el-icon-medal row-ico row-ico--primary" />
  261 + {{ cellText(s.row['品牌名称'] || s.row['商品名称']) }}
  262 + </template>
  263 + </el-table-column>
  264 + <el-table-column label="数量" width="88" align="right" sortable :sort-method="sortNumCol('数量')">
  265 + <template slot-scope="s">{{ formatQty(s.row['数量']) }}</template>
  266 + </el-table-column>
  267 + <el-table-column label="入库单价" width="100" align="right" sortable :sort-method="sortNumCol('入库单价')">
  268 + <template slot-scope="s">{{ formatMoney(s.row['入库单价']) }}</template>
  269 + </el-table-column>
  270 + <el-table-column label="采购金额" width="108" align="right" sortable :sort-method="sortNumCol('采购金额')">
  271 + <template slot-scope="s">{{ formatMoney(s.row['采购金额']) }}</template>
  272 + </el-table-column>
  273 + </el-table>
  274 + <div v-if="!(brandMap[categoryRowKey(catScope.row)] || []).length && !brandLoading[categoryRowKey(catScope.row)]" class="nested-empty">暂无品牌数据</div>
  275 + </div>
153 276 </template>
154 277 </el-table-column>
155   - <el-table-column prop="入库单价" label="入库单价" width="110" align="right">
  278 + <el-table-column type="index" label="行号" width="56" align="center" />
  279 + <el-table-column label="分类名称" min-width="160" show-overflow-tooltip sortable :sort-method="sortTextCol('分类名称')">
156 280 <template slot-scope="scope">
157   - {{ formatMoney(scope.row['入库单价']) }}
  281 + <i class="el-icon-folder-opened row-ico row-ico--primary" />
  282 + {{ cellText(scope.row['分类名称']) }}
158 283 </template>
159 284 </el-table-column>
160   - <el-table-column prop="采购金额" label="采购金额" width="120" align="right">
  285 + <el-table-column label="数量" width="96" align="right" sortable :sort-method="sortNumCol('数量')">
  286 + <template slot-scope="scope">{{ formatQty(scope.row['数量']) }}</template>
  287 + </el-table-column>
  288 + <el-table-column label="入库单价" width="104" align="right" sortable :sort-method="sortNumCol('入库单价')">
  289 + <template slot-scope="scope">{{ formatMoney(scope.row['入库单价']) }}</template>
  290 + </el-table-column>
  291 + <el-table-column label="采购金额" width="112" align="right" sortable :sort-method="sortNumCol('采购金额')">
  292 + <template slot-scope="scope">{{ formatMoney(scope.row['采购金额']) }}</template>
  293 + </el-table-column>
  294 + <el-table-column label="操作" width="120" align="left" fixed="right">
161 295 <template slot-scope="scope">
162   - {{ formatMoney(scope.row['采购金额']) }}
  296 + <el-button type="text" size="mini" icon="el-icon-tickets" @click.stop="openLinearDialog(scope.row)">线性列表</el-button>
163 297 </template>
164 298 </el-table-column>
165 299 </el-table>
166   - <div class="pager-wrap">
167   - <el-pagination
168   - :current-page="pagination.currentPage"
169   - :page-sizes="[50, 100, 200, 500]"
170   - :page-size="pagination.pageSize"
171   - layout="total, sizes, prev, pager, next, jumper"
172   - :total="pagination.total"
173   - @size-change="handleSizeChange"
174   - @current-change="handleCurrentChange"
175   - />
  300 +
  301 + <div v-if="categoryList.length" class="purchase-sum-footer">
  302 + <i class="el-icon-s-data row-ico--primary" />
  303 + <span>合计(当前分类列表)</span>
  304 + <span class="sum-item">数量:{{ formatQty(sumCategoryQty) }}</span>
  305 + <span class="sum-item">采购金额:{{ formatMoney(sumCategoryAmt) }}</span>
176 306 </div>
177 307 </div>
178 308 </div>
  309 +
  310 + <el-dialog
  311 + title="线性列表 — 分类下全部采购明细"
  312 + :visible.sync="linearVisible"
  313 + width="1180px"
  314 + top="5vh"
  315 + append-to-body
  316 + class="NCC-dialog NCC-dialog_center"
  317 + @close="linearRows = []"
  318 + >
  319 + <div v-loading="linearLoading" class="linear-dialog-body">
  320 + <p class="linear-hint">{{ linearHint }}</p>
  321 + <el-table :data="linearRows" border size="small" max-height="520" class="linear-table">
  322 + <el-table-column type="index" label="行号" width="52" />
  323 + <el-table-column prop="单据日期" label="单据日期" width="100" show-overflow-tooltip sortable :sort-method="sortTextCol('单据日期')" />
  324 + <el-table-column prop="单据编号" label="单据编号" min-width="130" show-overflow-tooltip sortable :sort-method="sortTextCol('单据编号')" />
  325 + <el-table-column prop="单据类型" label="单据类型" width="100" show-overflow-tooltip />
  326 + <el-table-column prop="往来单位" label="往来单位" min-width="110" show-overflow-tooltip />
  327 + <el-table-column prop="经手人" label="经手人" width="80" show-overflow-tooltip />
  328 + <el-table-column prop="仓库名称" label="仓库名称" min-width="96" show-overflow-tooltip />
  329 + <el-table-column prop="商品名称" label="商品名称" min-width="120" show-overflow-tooltip />
  330 + <el-table-column prop="数量" label="数量" width="80" align="right" sortable :sort-method="sortNumCol('数量')">
  331 + <template slot-scope="s">{{ formatQty(s.row['数量']) }}</template>
  332 + </el-table-column>
  333 + <el-table-column prop="入库单价" label="入库单价" width="92" align="right">
  334 + <template slot-scope="s">{{ formatMoney(s.row['入库单价']) }}</template>
  335 + </el-table-column>
  336 + <el-table-column prop="采购金额" label="采购金额" width="100" align="right" sortable :sort-method="sortNumCol('采购金额')">
  337 + <template slot-scope="s">{{ formatMoney(s.row['采购金额']) }}</template>
  338 + </el-table-column>
  339 + </el-table>
  340 + </div>
  341 + </el-dialog>
179 342 </div>
180 343 </template>
181 344  
... ... @@ -183,37 +346,84 @@
183 346 import request from '@/utils/request'
184 347 import { previewDataInterface } from '@/api/systemData/dataInterface'
185 348  
  349 +const DEFAULT_BILL_TYPES = ['采购入库单', '采购退货单']
  350 +
186 351 export default {
187 352 name: 'PurchaseSummary',
188   -
189 353 data() {
190 354 return {
191   - list: [],
192   - billTypeOptions: ['采购入库单', '采购退货单'],
  355 + categoryList: [],
  356 + categoryLoading: false,
  357 + brandMap: {},
  358 + brandLoading: {},
  359 + productMap: {},
  360 + productLoading: {},
  361 + lineMap: {},
  362 + linePager: {},
  363 + lineLoading: {},
  364 + billTypeOptions: [...DEFAULT_BILL_TYPES],
193 365 filters: {
194 366 dateRange: [],
195 367 contactUnit: [],
196 368 agent: [],
197   - productName: '',
  369 + productSpId: '',
198 370 warehouse: [],
199   - billType: ['采购入库单', '采购退货单']
  371 + billType: [...DEFAULT_BILL_TYPES]
200 372 },
201 373 contactUnitOptions: [],
202 374 agentOptions: [],
203 375 warehouseOptions: [],
204 376 productOptions: [],
205 377 productLoading: false,
206   - pagination: {
207   - currentPage: 1,
208   - pageSize: 100,
209   - total: 0
210   - }
  378 + linearVisible: false,
  379 + linearLoading: false,
  380 + linearRows: [],
  381 + linearHint: ''
211 382 }
212 383 },
213   -
  384 + computed: {
  385 + sumCategoryQty() {
  386 + return this.categoryList.reduce((s, r) => s + this.parseNum(r['数量']), 0)
  387 + },
  388 + sumCategoryAmt() {
  389 + return this.categoryList.reduce((s, r) => s + this.parseNum(r['采购金额']), 0)
  390 + }
  391 + },
  392 + created() {
  393 + this.loadFilterOptions()
  394 + this.fetchCategories()
  395 + },
214 396 methods: {
215   - indexMethod(index) {
216   - return (this.pagination.currentPage - 1) * this.pagination.pageSize + index + 1
  397 + categoryRowKey(row) {
  398 + return String(row['分类Id'] != null ? row['分类Id'] : '')
  399 + },
  400 + brandRowKey(catRow, brandRow) {
  401 + return `${this.categoryRowKey(catRow)}|${String(brandRow['品牌Id'] != null ? brandRow['品牌Id'] : '')}`
  402 + },
  403 + productRowKey(catRow, brandRow, prodRow) {
  404 + return `${this.brandRowKey(catRow, brandRow)}|${String(prodRow['商品Id'] != null ? prodRow['商品Id'] : '')}`
  405 + },
  406 + lineKey(catRow, brandRow, prodRow) {
  407 + return this.productRowKey(catRow, brandRow, prodRow)
  408 + },
  409 + parseNum(val) {
  410 + if (val == null || val === '') return 0
  411 + const n = Number(String(val).replace(/,/g, '').trim())
  412 + return Number.isFinite(n) ? n : 0
  413 + },
  414 + sortNumCol(prop) {
  415 + return (a, b) => this.parseNum(a[prop]) - this.parseNum(b[prop])
  416 + },
  417 + sortTextCol(prop) {
  418 + return (a, b) => {
  419 + const sa = String(a[prop] != null ? a[prop] : '').trim()
  420 + const sb = String(b[prop] != null ? b[prop] : '').trim()
  421 + return sa.localeCompare(sb, 'zh-CN')
  422 + }
  423 + },
  424 + cellText(v) {
  425 + if (v == null || String(v).trim() === '') return '无'
  426 + return String(v)
217 427 },
218 428 formatQty(val) {
219 429 if (val === null || val === undefined || val === '') return '无'
... ... @@ -227,6 +437,62 @@ export default {
227 437 if (Number.isNaN(n)) return String(val)
228 438 return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 4 })
229 439 },
  440 + /** 商品编码(空则返回空串,便于单行展示) */
  441 + productCodeRaw(item) {
  442 + if (!item) return ''
  443 + const c =
  444 + item.F_Spbm ||
  445 + item.spbm ||
  446 + item.Spbm ||
  447 + item.商品编号 ||
  448 + item.code ||
  449 + ''
  450 + const t = c != null && String(c).trim() !== '' ? String(c).trim() : ''
  451 + return t
  452 + },
  453 + /** 商品名称 */
  454 + productNameRaw(item) {
  455 + if (!item) return ''
  456 + const n =
  457 + item.F_Spmc ||
  458 + item.spmc ||
  459 + item.Spmc ||
  460 + item.productName ||
  461 + item.商品名称 ||
  462 + item.name ||
  463 + ''
  464 + const t = n != null && String(n).trim() !== '' ? String(n).trim() : ''
  465 + return t
  466 + },
  467 + /** 选中后在输入框内显示的完整文案(编码 + 名称) */
  468 + formatProductLabel(item) {
  469 + if (!item) return ''
  470 + const code = this.productCodeRaw(item)
  471 + const name = this.productNameRaw(item)
  472 + if (code && name) return `${code} | ${name}`
  473 + if (name) return name
  474 + if (code) return code
  475 + const id = item.F_Id || item.id
  476 + return id ? String(id) : '无'
  477 + },
  478 + buildBasePayload() {
  479 + const payload = {}
  480 + if (this.filters.dateRange && this.filters.dateRange.length === 2) {
  481 + payload.startDate = this.filters.dateRange[0]
  482 + payload.endDate = this.filters.dateRange[1]
  483 + }
  484 + if (this.filters.contactUnit.length) payload.contactUnit = this.filters.contactUnit.join(',')
  485 + if (this.filters.agent.length) payload.agent = this.filters.agent.join(',')
  486 + if (this.filters.warehouse.length) payload.warehouse = this.filters.warehouse.join(',')
  487 + if (this.filters.productSpId) payload.productSpId = this.filters.productSpId
  488 + const bt = this.filters.billType || []
  489 + if (bt.length > 0 && bt.length < this.billTypeOptions.length) {
  490 + payload.billType = bt.join(',')
  491 + } else {
  492 + payload.billType = ''
  493 + }
  494 + return payload
  495 + },
230 496 async loadFilterOptions() {
231 497 try {
232 498 const companyRes = await request({
... ... @@ -255,9 +521,12 @@ export default {
255 521  
256 522 const userRes = await previewDataInterface('675937572047815941')
257 523 const userList = userRes.data || []
258   - this.agentOptions = Array.from(
259   - new Set(userList.map(x => x.realName || x.F_RealName || x.fullName).filter(Boolean))
260   - )
  524 + this.agentOptions = (userList || [])
  525 + .map(x => ({
  526 + label: x.realName || x.F_RealName || x.fullName || x.name || x.F_Account || x.account || '',
  527 + value: x.id || x.F_Id || x.userId
  528 + }))
  529 + .filter(x => x.value && x.label)
261 530 } catch (e) {
262 531 console.error('采购汇总筛选下拉加载失败', e)
263 532 }
... ... @@ -270,7 +539,7 @@ export default {
270 539 this.productLoading = true
271 540 try {
272 541 const res = await request({
273   - url: '/api/Extend/WtSp',
  542 + url: '/api/Extend/WtSp/GetListByKeyword',
274 543 method: 'GET',
275 544 data: { pageSize: 200, currentPage: 1, keyword: query }
276 545 })
... ... @@ -281,138 +550,320 @@ export default {
281 550 this.productLoading = false
282 551 }
283 552 },
284   - formatProductLabel(item) {
285   - if (!item) return ''
286   - const code = item.spbm || item.productCode || item.商品编号 || item.code || item.F_Id || item.id || ''
287   - const name = item.F_Spmc || item.productName || item.商品名称 || item.name || ''
288   - return [code, name].filter(Boolean).join(' ')
  553 + clearTreeCaches() {
  554 + this.brandMap = {}
  555 + this.brandLoading = {}
  556 + this.productMap = {}
  557 + this.productLoading = {}
  558 + this.lineMap = {}
  559 + this.linePager = {}
  560 + this.lineLoading = {}
289 561 },
290   - buildQueryPayload() {
291   - const payload = {}
292   - if (this.filters.dateRange && this.filters.dateRange.length === 2) {
293   - payload.startDate = this.filters.dateRange[0]
294   - payload.endDate = this.filters.dateRange[1]
  562 + fetchCategories() {
  563 + this.categoryLoading = true
  564 + this.clearTreeCaches()
  565 + request({
  566 + url: '/api/Extend/WtXsckd/Actions/GetPurchaseSummaryByCategory',
  567 + method: 'GET',
  568 + data: this.buildBasePayload()
  569 + })
  570 + .then(res => {
  571 + const rows = Array.isArray(res.data) ? res.data : (res.data && res.data.list) || []
  572 + this.categoryList = rows
  573 + })
  574 + .catch(() => {
  575 + this.categoryList = []
  576 + })
  577 + .finally(() => {
  578 + this.categoryLoading = false
  579 + })
  580 + },
  581 + onCategoryExpand(row, expandedRows) {
  582 + const id = String(row['分类Id'])
  583 + if (expandedRows.some(r => String(r['分类Id']) === id)) {
  584 + this.loadBrands(row)
295 585 }
296   - if (this.filters.productName) payload.product = this.filters.productName
297   - if (this.filters.contactUnit.length) payload.contactUnit = this.filters.contactUnit.join(',')
298   - if (this.filters.agent.length) payload.agent = this.filters.agent.join(',')
299   - if (this.filters.warehouse.length) payload.warehouse = this.filters.warehouse.join(',')
300   -
301   - if (this.filters.billType.length > 0 && this.filters.billType.length < this.billTypeOptions.length) {
302   - payload.billType = this.filters.billType.join(',')
303   - } else {
304   - payload.billType = ''
  586 + },
  587 + loadBrands(catRow) {
  588 + const k = this.categoryRowKey(catRow)
  589 + if (this.brandMap[k] !== undefined || this.brandLoading[k]) return
  590 + this.$set(this.brandLoading, k, true)
  591 + const cid = String(catRow['分类Id'] != null ? catRow['分类Id'] : '')
  592 + request({
  593 + url: '/api/Extend/WtXsckd/Actions/GetPurchaseSummaryByBrand',
  594 + method: 'GET',
  595 + data: { ...this.buildBasePayload(), categoryId: cid }
  596 + })
  597 + .then(res => {
  598 + const rows = Array.isArray(res.data) ? res.data : (res.data && res.data.list) || []
  599 + this.$set(this.brandMap, k, rows)
  600 + })
  601 + .catch(() => {
  602 + this.$set(this.brandMap, k, [])
  603 + })
  604 + .finally(() => {
  605 + this.$set(this.brandLoading, k, false)
  606 + })
  607 + },
  608 + onBrandExpand(catRow, brandRow, expandedRows) {
  609 + if (expandedRows.some(r => this.brandRowKey(catRow, r) === this.brandRowKey(catRow, brandRow))) {
  610 + this.loadProducts(catRow, brandRow)
305 611 }
306   - payload.currentPage = this.pagination.currentPage
307   - payload.pageSize = this.pagination.pageSize
308   - return payload
309 612 },
310   - handleSearch() {
311   - this.pagination.currentPage = 1
312   - this.fetchData()
  613 + loadProducts(catRow, brandRow) {
  614 + const k = this.brandRowKey(catRow, brandRow)
  615 + if (this.productMap[k] !== undefined || this.productLoading[k]) return
  616 + this.$set(this.productLoading, k, true)
  617 + const cid = String(catRow['分类Id'] != null ? catRow['分类Id'] : '')
  618 + const bid = String(brandRow['品牌Id'] != null ? brandRow['品牌Id'] : '')
  619 + request({
  620 + url: '/api/Extend/WtXsckd/Actions/GetPurchaseSummaryByProductAgg',
  621 + method: 'GET',
  622 + data: { ...this.buildBasePayload(), categoryId: cid, brandId: bid }
  623 + })
  624 + .then(res => {
  625 + const rows = Array.isArray(res.data) ? res.data : (res.data && res.data.list) || []
  626 + this.$set(this.productMap, k, rows)
  627 + })
  628 + .catch(() => {
  629 + this.$set(this.productMap, k, [])
  630 + })
  631 + .finally(() => {
  632 + this.$set(this.productLoading, k, false)
  633 + })
313 634 },
314   - fetchData() {
315   - const payload = this.buildQueryPayload()
  635 + onProductExpand(catRow, brandRow, prodRow, expandedRows) {
  636 + if (expandedRows.some(r => this.productRowKey(catRow, brandRow, r) === this.productRowKey(catRow, brandRow, prodRow))) {
  637 + this.initLinePager(catRow, brandRow, prodRow)
  638 + this.fetchLines(catRow, brandRow, prodRow, 1)
  639 + }
  640 + },
  641 + initLinePager(catRow, brandRow, prodRow) {
  642 + const lk = this.lineKey(catRow, brandRow, prodRow)
  643 + if (!this.linePager[lk]) {
  644 + this.$set(this.linePager, lk, { currentPage: 1, pageSize: 50, total: 0 })
  645 + }
  646 + },
  647 + fetchLines(catRow, brandRow, prodRow, page) {
  648 + const lk = this.lineKey(catRow, brandRow, prodRow)
  649 + this.initLinePager(catRow, brandRow, prodRow)
  650 + const pager = this.linePager[lk]
  651 + pager.currentPage = page || 1
  652 + this.$set(this.lineLoading, lk, true)
  653 + const cid = String(catRow['分类Id'] != null ? catRow['分类Id'] : '')
  654 + const bid = String(brandRow['品牌Id'] != null ? brandRow['品牌Id'] : '')
  655 + const pid = String(prodRow['商品Id'] != null ? prodRow['商品Id'] : '')
316 656 request({
317   - url: `/api/Extend/WtXsckd/Actions/GetPurchaseSummary`,
  657 + url: '/api/Extend/WtXsckd/Actions/GetPurchaseSummary',
318 658 method: 'GET',
319   - data: payload
320   - }).then(res => {
321   - const body = res.data
322   - if (body && typeof body === 'object' && !Array.isArray(body) && body.list !== undefined) {
323   - this.list = body.list || []
324   - this.pagination.total = body.total != null ? Number(body.total) : 0
325   - } else if (Array.isArray(body)) {
326   - this.list = body
327   - this.pagination.total = body.length
328   - } else {
329   - this.list = []
330   - this.pagination.total = 0
  659 + data: {
  660 + ...this.buildBasePayload(),
  661 + categoryId: cid,
  662 + brandId: bid,
  663 + productSpId: pid,
  664 + currentPage: pager.currentPage,
  665 + pageSize: pager.pageSize
331 666 }
332 667 })
  668 + .then(res => {
  669 + const body = res.data
  670 + let list = []
  671 + let total = 0
  672 + if (body && typeof body === 'object' && !Array.isArray(body) && body.list !== undefined) {
  673 + list = body.list || []
  674 + total = body.total != null ? Number(body.total) : 0
  675 + } else if (Array.isArray(body)) {
  676 + list = body
  677 + total = body.length
  678 + }
  679 + this.$set(this.lineMap, lk, { list })
  680 + this.$set(this.linePager[lk], 'total', total)
  681 + })
  682 + .catch(() => {
  683 + this.$set(this.lineMap, lk, { list: [] })
  684 + })
  685 + .finally(() => {
  686 + this.$set(this.lineLoading, lk, false)
  687 + })
333 688 },
334   - handleSizeChange(size) {
335   - this.pagination.pageSize = size
336   - this.pagination.currentPage = 1
337   - this.fetchData()
  689 + openLinearDialog(catRow) {
  690 + const cid = String(catRow['分类Id'] != null ? catRow['分类Id'] : '')
  691 + const cname = this.cellText(catRow['分类名称'])
  692 + this.linearHint = `分类:${cname}(最多展示 2000 条,与当前筛选条件一致)`
  693 + this.linearVisible = true
  694 + this.linearLoading = true
  695 + this.linearRows = []
  696 + request({
  697 + url: '/api/Extend/WtXsckd/Actions/GetPurchaseSummaryLinear',
  698 + method: 'GET',
  699 + data: { ...this.buildBasePayload(), categoryId: cid }
  700 + })
  701 + .then(res => {
  702 + this.linearRows = Array.isArray(res.data) ? res.data : (res.data && res.data.list) || []
  703 + })
  704 + .catch(() => {
  705 + this.linearRows = []
  706 + })
  707 + .finally(() => {
  708 + this.linearLoading = false
  709 + })
338 710 },
339   - handleCurrentChange(page) {
340   - this.pagination.currentPage = page
341   - this.fetchData()
  711 + handleSearch() {
  712 + this.fetchCategories()
342 713 },
343 714 handleReset() {
344 715 this.filters = {
345 716 dateRange: [],
346 717 contactUnit: [],
347 718 agent: [],
348   - productName: '',
  719 + productSpId: '',
349 720 warehouse: [],
350   - billType: [...this.billTypeOptions]
  721 + billType: [...DEFAULT_BILL_TYPES]
351 722 }
352   - this.pagination.currentPage = 1
353   - this.fetchData()
  723 + this.productOptions = []
  724 + this.fetchCategories()
354 725 }
355   - },
356   - created() {
357   - this.loadFilterOptions()
358   - this.fetchData()
359 726 }
360 727 }
361 728 </script>
362 729  
363   -<style scoped>
364   -.purchase-summary-page {
365   - width: 100%;
366   - min-height: 100%;
367   - background: #f9f9f9;
368   - padding: 10px 20px;
369   - box-sizing: border-box;
  730 +<style lang="scss" scoped>
  731 +.purchase-sum-head {
  732 + align-items: center;
  733 + margin-bottom: 8px;
  734 +}
  735 +
  736 +.purchase-sum-head__title {
  737 + font-size: 15px;
  738 + font-weight: 600;
  739 + color: #303133;
  740 + display: inline-flex;
  741 + align-items: center;
  742 + gap: 8px;
370 743 }
371 744  
372   -.form-section {
373   - background: #fff;
374   - border-radius: 6px;
375   - padding: 10px 10px 0 10px;
376   - margin-bottom: 10px;
  745 +.purchase-sum-head__icon {
  746 + color: #409eff;
  747 + font-size: 18px;
  748 +}
  749 +
  750 +.purchase-tree-table {
  751 + ::v-deep .el-table .cell {
  752 + white-space: nowrap;
  753 + }
  754 +}
  755 +
  756 +.nested-wrap {
  757 + padding: 8px 8px 8px 24px;
  758 + background: #fafbfc;
377 759 }
378 760  
379   -.table-section {
380   - background: #fff;
381   - border-radius: 6px;
382   - padding: 12px 12px 10px 12px;
383   - margin: 0;
  761 +.nested-table {
384 762 width: 100%;
385   - box-sizing: border-box;
386 763 }
387 764  
388   -.action-row {
389   - display: flex;
390   - justify-content: flex-start;
391   - gap: 8px;
392   - padding: 4px 0 10px;
  765 +.nested-table--deep ::v-deep .el-table__body-wrapper {
  766 + max-height: 320px;
  767 + overflow-y: auto;
393 768 }
394 769  
395   -.table-title-bar {
396   - font-size: 18px;
397   - font-weight: bold;
398   - margin-bottom: 10px;
  770 +.detail-wrap {
  771 + min-width: 720px;
  772 +}
  773 +
  774 +.mini-pager {
  775 + margin-top: 8px;
  776 + text-align: left;
  777 +}
  778 +
  779 +.nested-empty {
  780 + padding: 12px;
  781 + color: #909399;
  782 + font-size: 13px;
  783 +}
  784 +
  785 +.row-ico {
  786 + margin-right: 4px;
  787 +}
  788 +
  789 +.row-ico--primary {
  790 + color: #409eff;
  791 +}
  792 +
  793 +.row-ico--info {
  794 + color: #909399;
  795 +}
  796 +
  797 +.row-ico--muted {
  798 + color: #c0c4cc;
  799 +}
  800 +
  801 +.purchase-sum-footer {
  802 + margin-top: 12px;
  803 + padding: 10px 12px;
  804 + background: #f5f7fa;
  805 + border-radius: 8px;
  806 + font-size: 13px;
  807 + color: #606266;
399 808 display: flex;
  809 + flex-wrap: wrap;
400 810 align-items: center;
401   - gap: 12px;
  811 + gap: 16px;
402 812 }
403 813  
404   -.table-scroll {
405   - max-height: calc(100vh - 300px);
406   - overflow-y: auto;
  814 +.sum-item {
  815 + font-weight: 600;
  816 + color: #303133;
407 817 }
408 818  
409   -.pager-wrap {
410   - display: flex;
411   - justify-content: flex-start;
412   - padding: 12px 0 4px;
  819 +.linear-dialog-body {
  820 + min-height: 120px;
413 821 }
414 822  
415   -.purchase-record-table ::v-deep .cell {
  823 +.linear-hint {
  824 + font-size: 12px;
  825 + color: #909399;
  826 + margin: 0 0 10px;
  827 +}
  828 +
  829 +.linear-table ::v-deep .el-table .cell {
416 830 white-space: nowrap;
417 831 }
  832 +
  833 +/* 商品远程下拉:单行「编码 | 名称」,避免多行标签错位 */
  834 +.product-opt-row {
  835 + display: flex;
  836 + align-items: center;
  837 + max-width: 100%;
  838 + font-size: 13px;
  839 + line-height: 1.4;
  840 +}
  841 +
  842 +.product-opt-code {
  843 + flex-shrink: 0;
  844 + color: #606266;
  845 + font-weight: 600;
  846 +}
  847 +
  848 +.product-opt-sep {
  849 + flex-shrink: 0;
  850 + margin: 0 6px;
  851 + color: #dcdfe6;
  852 +}
  853 +
  854 +.product-opt-name {
  855 + flex: 1;
  856 + min-width: 0;
  857 + overflow: hidden;
  858 + text-overflow: ellipsis;
  859 + color: #303133;
  860 +}
  861 +</style>
  862 +
  863 +<!-- 下拉挂到 body,需非 scoped 才能命中 popper -->
  864 +<style lang="scss">
  865 +.wt-purchase-sum-product-dropdown.el-select-dropdown {
  866 + min-width: 420px !important;
  867 + max-width: min(720px, 92vw);
  868 +}
418 869 </style>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtSfk/Form.vue
... ... @@ -91,8 +91,8 @@
91 91 </template>
92 92 <script>
93 93 import request from '@/utils/request'
94   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
95 94 import { previewDataInterface } from '@/api/systemData/dataInterface'
  95 + import { getAccountSelector } from '@/api/extend/wtAccount'
96 96 export default {
97 97 components: {},
98 98 props: [],
... ... @@ -138,7 +138,7 @@
138 138 });
139 139 },
140 140 getjszhOptions(){
141   - getDictionaryDataSelector('681761709836207365').then(res => {
  141 + getAccountSelector().then(res => {
142 142 this.jszhOptions = res.data.list
143 143 });
144 144 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtSfk/index.vue
... ... @@ -127,10 +127,10 @@
127 127 </template>
128 128 <script>
129 129 import request from '@/utils/request'
130   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
131 130 import NCCForm from './Form'
132 131 import ExportBox from './ExportBox'
133 132 import { previewDataInterface } from '@/api/systemData/dataInterface'
  133 + import { getAccountSelector } from '@/api/extend/wtAccount'
134 134 export default {
135 135 components: { NCCForm, ExportBox },
136 136 data() {
... ... @@ -190,7 +190,7 @@
190 190 });
191 191 },
192 192 getjszhOptions(){
193   - getDictionaryDataSelector('681761709836207365').then(res => {
  193 + getAccountSelector().then(res => {
194 194 this.jszhOptions = res.data.list
195 195 });
196 196 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtSkzhb/Form.vue
... ... @@ -32,8 +32,8 @@
32 32 </template>
33 33 <script>
34 34 import request from '@/utils/request'
35   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
36 35 import { previewDataInterface } from '@/api/systemData/dataInterface'
  36 + import { getAccountSelector } from '@/api/extend/wtAccount'
37 37 export default {
38 38 components: {},
39 39 props: [],
... ... @@ -65,7 +65,7 @@
65 65 methods: {
66 66 // ✅ 获取账户名称选项(从数据字典)
67 67 getzhmcOptions(){
68   - getDictionaryDataSelector('681761709836207365').then(res => {
  68 + getAccountSelector().then(res => {
69 69 this.zhmcOptions = res.data.list || [];
70 70 }).catch(() => {
71 71 this.zhmcOptions = [];
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtSkzhb/account-form.vue 0 → 100644
  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="600px">
  3 + <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :rules="rules">
  4 + <el-row :gutter="15">
  5 + <el-col :span="24">
  6 + <el-form-item label="账户名称" prop="accountName">
  7 + <el-input v-model="dataForm.accountName" placeholder="请输入账户名称" clearable />
  8 + </el-form-item>
  9 + </el-col>
  10 + <el-col :span="24">
  11 + <el-form-item label="业务编码" prop="accountCode">
  12 + <el-input v-model="dataForm.accountCode" placeholder="留空自动生成" clearable />
  13 + </el-form-item>
  14 + </el-col>
  15 + <el-col :span="24" v-if="!dataForm.id && !dataForm.accountCode">
  16 + <el-form-item label="编码规则" prop="codeRule">
  17 + <el-radio-group v-model="dataForm.codeRule">
  18 + <el-radio :label="1">数字序号</el-radio>
  19 + <el-radio :label="2">拼音缩写</el-radio>
  20 + </el-radio-group>
  21 + </el-form-item>
  22 + </el-col>
  23 + <el-col :span="24">
  24 + <el-form-item label="账户分类" prop="category">
  25 + <el-select v-model="dataForm.category" placeholder="请选择或输入分类" clearable filterable allow-create default-first-option style="width:100%">
  26 + <el-option v-for="item in categoryOptions" :key="item" :label="item" :value="item" />
  27 + </el-select>
  28 + </el-form-item>
  29 + </el-col>
  30 + <el-col :span="24">
  31 + <el-form-item label="排序码" prop="sortCode">
  32 + <el-input-number v-model="dataForm.sortCode" :min="0" :step="1" controls-position="right" style="width:100%" />
  33 + </el-form-item>
  34 + </el-col>
  35 + <el-col :span="24" v-if="dataForm.id">
  36 + <el-form-item label="状态" prop="status">
  37 + <el-radio-group v-model="dataForm.status">
  38 + <el-radio :label="1">启用</el-radio>
  39 + <el-radio :label="0">禁用</el-radio>
  40 + </el-radio-group>
  41 + </el-form-item>
  42 + </el-col>
  43 + </el-row>
  44 + </el-form>
  45 + <span slot="footer" class="dialog-footer">
  46 + <el-button @click="visible = false">取 消</el-button>
  47 + <el-button type="primary" :loading="btnLoading" @click="dataFormSubmit()">确 定</el-button>
  48 + </span>
  49 + </el-dialog>
  50 +</template>
  51 +<script>
  52 +import { getAccountInfo, createAccount, updateAccount, getAccountCategories } from '@/api/extend/wtAccount'
  53 +export default {
  54 + data() {
  55 + return {
  56 + visible: false,
  57 + btnLoading: false,
  58 + categoryOptions: [],
  59 + dataForm: {
  60 + id: '',
  61 + accountName: '',
  62 + accountCode: '',
  63 + codeRule: 1,
  64 + category: '',
  65 + sortCode: 0,
  66 + status: 1
  67 + },
  68 + rules: {
  69 + accountName: [{ required: true, message: '请输入账户名称', trigger: 'blur' }]
  70 + }
  71 + }
  72 + },
  73 + methods: {
  74 + init(id) {
  75 + this.dataForm.id = id || ''
  76 + this.visible = true
  77 + this.loadCategories()
  78 + this.$nextTick(function () {
  79 + this.$refs['elForm'].resetFields()
  80 + if (this.dataForm.id) {
  81 + getAccountInfo(this.dataForm.id).then(function (res) {
  82 + this.dataForm = res.data
  83 + }.bind(this))
  84 + } else {
  85 + this.dataForm.codeRule = 1
  86 + this.dataForm.sortCode = 0
  87 + this.dataForm.status = 1
  88 + }
  89 + })
  90 + },
  91 + loadCategories() {
  92 + getAccountCategories().then(function (res) {
  93 + this.categoryOptions = res.data || []
  94 + }.bind(this)).catch(function () {
  95 + this.categoryOptions = []
  96 + }.bind(this))
  97 + },
  98 + dataFormSubmit() {
  99 + this.$refs['elForm'].validate(function (valid) {
  100 + if (!valid) return
  101 + this.btnLoading = true
  102 + var body = {
  103 + accountName: this.dataForm.accountName,
  104 + accountCode: this.dataForm.accountCode,
  105 + category: this.dataForm.category,
  106 + sortCode: this.dataForm.sortCode
  107 + }
  108 + var promise
  109 + if (!this.dataForm.id) {
  110 + body.codeRule = this.dataForm.codeRule
  111 + promise = createAccount(body)
  112 + } else {
  113 + body.status = this.dataForm.status
  114 + promise = updateAccount(this.dataForm.id, body)
  115 + }
  116 + promise.then(function (res) {
  117 + this.btnLoading = false
  118 + this.$message({
  119 + message: res.msg,
  120 + type: 'success',
  121 + duration: 1000,
  122 + onClose: function () {
  123 + this.visible = false
  124 + this.$emit('refresh', true)
  125 + }.bind(this)
  126 + })
  127 + }.bind(this)).catch(function () {
  128 + this.btnLoading = false
  129 + }.bind(this))
  130 + }.bind(this))
  131 + }
  132 + }
  133 +}
  134 +</script>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtSkzhb/index.vue
1 1 <template>
2 2 <div class="NCC-common-layout">
3 3 <div class="NCC-common-layout-center">
4   - <el-row class="NCC-common-search-box" :gutter="16">
5   - <el-form @submit.native.prevent>
6   - <el-col :span="6">
7   - <el-form-item label="账户编号">
8   - <el-input v-model="query.id" placeholder="账户编号" clearable />
9   - </el-form-item>
10   - </el-col>
11   - <el-col :span="6">
12   - <el-form-item label="账户名称">
13   - <el-select v-model="query.zhmc" placeholder="请选择账户名称" clearable :style='{"width":"100%"}' >
14   - <el-option v-for="(item, index) in zhmcOptions" :key="index" :label="item.fullName" :value="item.id" ></el-option>
15   - </el-select>
16   - </el-form-item>
17   - </el-col>
18   - <el-col :span="6">
19   - <el-form-item label="所属门店">
20   - <el-select v-model="query.ssmd" placeholder="请选择门店" clearable :style='{"width":"100%"}' >
21   - <el-option v-for="(item, index) in ssmdOptions" :key="index" :label="item.F_Mdmc" :value="item.F_Id" ></el-option>
22   - </el-select>
23   - </el-form-item>
24   - </el-col>
25   - <el-col :span="6">
26   - <el-form-item>
27   - <el-button type="primary" icon="el-icon-search" @click="search()">查询</el-button>
28   - <el-button icon="el-icon-refresh-right" @click="reset()">重置</el-button>
29   - </el-form-item>
30   - </el-col>
31   - </el-form>
32   - </el-row>
33   - <div class="NCC-common-layout-main NCC-flex-main">
34   - <div class="NCC-common-head">
35   - <div>
36   - <el-button type="primary" icon="el-icon-plus" @click="addOrUpdateHandle()">新增</el-button>
37   - <el-button type="text" icon="el-icon-download" @click="exportData()">导出</el-button>
38   - <el-button type="text" icon="el-icon-delete" @click="handleBatchRemoveDel()">批量删除</el-button>
  4 + <el-tabs v-model="activeTab" @tab-click="handleTabClick">
  5 + <el-tab-pane label="账户管理" name="account">
  6 + <!-- Tab1 搜索区 -->
  7 + <el-row class="NCC-common-search-box" :gutter="16">
  8 + <el-form @submit.native.prevent>
  9 + <el-col :span="6">
  10 + <el-form-item label="关键字">
  11 + <el-input v-model="accountQuery.keyword" placeholder="编码/名称模糊搜索" clearable />
  12 + </el-form-item>
  13 + </el-col>
  14 + <el-col :span="6">
  15 + <el-form-item label="账户分类">
  16 + <el-select v-model="accountQuery.category" placeholder="请选择分类" clearable style="width:100%">
  17 + <el-option v-for="item in categoryOptions" :key="item" :label="item" :value="item" />
  18 + </el-select>
  19 + </el-form-item>
  20 + </el-col>
  21 + <el-col :span="6">
  22 + <el-form-item label="状态">
  23 + <el-select v-model="accountQuery.status" placeholder="全部" clearable style="width:100%">
  24 + <el-option label="启用" :value="1" />
  25 + <el-option label="禁用" :value="0" />
  26 + </el-select>
  27 + </el-form-item>
  28 + </el-col>
  29 + <el-col :span="6">
  30 + <el-form-item>
  31 + <el-button type="primary" icon="el-icon-search" @click="accountSearch()">查询</el-button>
  32 + <el-button icon="el-icon-refresh-right" @click="accountReset()">重置</el-button>
  33 + </el-form-item>
  34 + </el-col>
  35 + </el-form>
  36 + </el-row>
  37 + <!-- Tab1 操作区 + 列表 -->
  38 + <div class="NCC-common-layout-main NCC-flex-main">
  39 + <div class="NCC-common-head">
  40 + <div>
  41 + <el-button type="primary" icon="el-icon-plus" @click="openAccountForm()">新增</el-button>
  42 + </div>
  43 + <div class="NCC-common-head-right">
  44 + <el-tooltip effect="dark" content="刷新" placement="top">
  45 + <el-link icon="icon-ym icon-ym-Refresh NCC-common-head-icon" :underline="false" @click="accountReset()" />
  46 + </el-tooltip>
  47 + <screenfull isContainer />
  48 + </div>
  49 + </div>
  50 + <NCC-table v-loading="accountLoading" :data="accountList">
  51 + <el-table-column prop="accountCode" label="业务编码" align="left" sortable />
  52 + <el-table-column prop="accountName" label="账户名称" align="left" sortable />
  53 + <el-table-column prop="category" label="账户分类" align="left">
  54 + <template slot-scope="scope">
  55 + {{ scope.row.category || '无' }}
  56 + </template>
  57 + </el-table-column>
  58 + <el-table-column prop="status" label="状态" align="left" width="100">
  59 + <template slot-scope="scope">
  60 + <el-tag v-if="scope.row.status === 1" type="success" size="mini">启用</el-tag>
  61 + <el-tag v-else type="info" size="mini">禁用</el-tag>
  62 + </template>
  63 + </el-table-column>
  64 + <el-table-column prop="sortCode" label="排序码" align="left" width="100" sortable />
  65 + <el-table-column label="操作" fixed="right" width="120">
  66 + <template slot-scope="scope">
  67 + <el-button type="text" @click="openAccountForm(scope.row.id)">编辑</el-button>
  68 + <el-button type="text" class="NCC-table-delBtn" @click="accountDel(scope.row.id)">删除</el-button>
  69 + </template>
  70 + </el-table-column>
  71 + </NCC-table>
  72 + <pagination :total="accountTotal" :page.sync="accountListQuery.currentPage" :limit.sync="accountListQuery.pageSize" @pagination="loadAccountList" />
39 73 </div>
40   - <div class="NCC-common-head-right">
41   - <el-tooltip effect="dark" content="刷新" placement="top">
42   - <el-link icon="icon-ym icon-ym-Refresh NCC-common-head-icon" :underline="false" @click="reset()" />
43   - </el-tooltip>
44   - <screenfull isContainer />
  74 + </el-tab-pane>
  75 +
  76 + <el-tab-pane label="门店账户授权" name="store">
  77 + <!-- Tab2 搜索区(原有) -->
  78 + <el-row class="NCC-common-search-box" :gutter="16">
  79 + <el-form @submit.native.prevent>
  80 + <el-col :span="6">
  81 + <el-form-item label="账户编号">
  82 + <el-input v-model="query.id" placeholder="账户编号" clearable />
  83 + </el-form-item>
  84 + </el-col>
  85 + <el-col :span="6">
  86 + <el-form-item label="账户名称">
  87 + <el-select v-model="query.zhmc" placeholder="请选择账户名称" clearable style="width:100%">
  88 + <el-option v-for="(item, index) in zhmcOptions" :key="index" :label="item.fullName" :value="item.id" />
  89 + </el-select>
  90 + </el-form-item>
  91 + </el-col>
  92 + <el-col :span="6">
  93 + <el-form-item label="所属门店">
  94 + <el-select v-model="query.ssmd" placeholder="请选择门店" clearable style="width:100%">
  95 + <el-option v-for="(item, index) in ssmdOptions" :key="index" :label="item.F_Mdmc" :value="item.F_Id" />
  96 + </el-select>
  97 + </el-form-item>
  98 + </el-col>
  99 + <el-col :span="6">
  100 + <el-form-item>
  101 + <el-button type="primary" icon="el-icon-search" @click="search()">查询</el-button>
  102 + <el-button icon="el-icon-refresh-right" @click="reset()">重置</el-button>
  103 + </el-form-item>
  104 + </el-col>
  105 + </el-form>
  106 + </el-row>
  107 + <!-- Tab2 操作区 + 列表(原有) -->
  108 + <div class="NCC-common-layout-main NCC-flex-main">
  109 + <div class="NCC-common-head">
  110 + <div>
  111 + <el-button type="primary" icon="el-icon-plus" @click="addOrUpdateHandle()">新增</el-button>
  112 + <el-button type="text" icon="el-icon-download" @click="exportData()">导出</el-button>
  113 + <el-button type="text" icon="el-icon-delete" @click="handleBatchRemoveDel()">批量删除</el-button>
  114 + </div>
  115 + <div class="NCC-common-head-right">
  116 + <el-tooltip effect="dark" content="刷新" placement="top">
  117 + <el-link icon="icon-ym icon-ym-Refresh NCC-common-head-icon" :underline="false" @click="reset()" />
  118 + </el-tooltip>
  119 + <screenfull isContainer />
  120 + </div>
  121 + </div>
  122 + <NCC-table v-loading="listLoading" :data="list" has-c @selection-change="handleSelectionChange">
  123 + <el-table-column prop="id" label="账户编号" align="left" />
  124 + <el-table-column prop="zhmc" label="账户名称" align="left" />
  125 + <el-table-column prop="ssmd" label="所属门店" align="left" />
  126 + <el-table-column label="操作" fixed="right" width="100">
  127 + <template slot-scope="scope">
  128 + <el-button type="text" @click="addOrUpdateHandle(scope.row.id)">编辑</el-button>
  129 + <el-button type="text" class="NCC-table-delBtn" @click="handleDel(scope.row.id)">删除</el-button>
  130 + </template>
  131 + </el-table-column>
  132 + </NCC-table>
  133 + <pagination :total="total" :page.sync="listQuery.currentPage" :limit.sync="listQuery.pageSize" @pagination="initData" />
45 134 </div>
46   - </div>
47   - <NCC-table v-loading="listLoading" :data="list" has-c @selection-change="handleSelectionChange">
48   - <el-table-column prop="id" label="账户编号" align="left" />
49   - <el-table-column prop="zhmc" label="账户名称" align="left" />
50   - <el-table-column prop="ssmd" label="所属门店" align="left" />
51   - <el-table-column label="操作" fixed="right" width="100">
52   - <template slot-scope="scope">
53   - <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
54   - <el-button type="text" @click="handleDel(scope.row.id)" class="NCC-table-delBtn" >删除</el-button>
55   - </template>
56   - </el-table-column>
57   - </NCC-table>
58   - <pagination :total="total" :page.sync="listQuery.currentPage" :limit.sync="listQuery.pageSize" @pagination="initData" />
59   - </div>
60   - </div>
  135 + </el-tab-pane>
  136 + </el-tabs>
  137 + </div>
  138 + <!-- Tab1 弹窗 -->
  139 + <AccountForm v-if="accountFormVisible" ref="AccountForm" @refresh="accountRefresh" />
  140 + <!-- Tab2 弹窗 -->
61 141 <NCC-Form v-if="formVisible" ref="NCCForm" @refresh="refresh" />
  142 + <!-- Tab2 导出 -->
62 143 <ExportBox v-if="exportBoxVisible" ref="ExportBox" @download="download" />
63 144 </div>
64 145 </template>
65 146 <script>
66   - import request from '@/utils/request'
67   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
68   - import NCCForm from './Form'
69   - import ExportBox from './ExportBox'
70   - import { previewDataInterface } from '@/api/systemData/dataInterface'
71   - export default {
72   - components: { NCCForm, ExportBox },
73   - data() {
74   - return {
75   - showAll: false,
76   - query: {
77   - id:undefined,
78   - zhmc:undefined,
79   - ssmd:undefined,
80   - },
81   - list: [],
82   - listLoading: true,
83   - multipleSelection: [], total: 0,
84   - listQuery: {
85   - currentPage: 1,
86   - pageSize: 20,
87   - sort: "desc",
88   - sidx: "",
89   - },
90   - formVisible: false,
91   - exportBoxVisible: false,
92   - columnList: [
93   - { prop: 'id', label: '账户编号' },
94   - { prop: 'zhmc', label: '账户名称' },
95   - { prop: 'ssmd', label: '所属门店' },
96   - ],
97   - zhmcOptions: [], // ✅ 账户名称选项(从数据字典获取)
98   - ssmdOptions: [], // ✅ 门店选项(从门店记录获取)
99   - }
100   - },
101   - computed: {},
102   - created() {
103   - this.initData();
104   - this.getzhmcOptions();
105   - this.getssmdOptions();
106   - },
107   - methods: {
108   - // ✅ 获取账户名称选项(从数据字典)
109   - getzhmcOptions(){
110   - getDictionaryDataSelector('681761709836207365').then(res => {
111   - this.zhmcOptions = res.data.list || [];
112   - }).catch(() => {
113   - this.zhmcOptions = [];
114   - });
  147 +import request from '@/utils/request'
  148 +import NCCForm from './Form'
  149 +import AccountForm from './account-form'
  150 +import ExportBox from './ExportBox'
  151 +import { previewDataInterface } from '@/api/systemData/dataInterface'
  152 +import {
  153 + getAccountSelector,
  154 + getAccountList,
  155 + deleteAccount,
  156 + getAccountCategories
  157 +} from '@/api/extend/wtAccount'
  158 +export default {
  159 + components: { NCCForm, AccountForm, ExportBox },
  160 + data() {
  161 + return {
  162 + activeTab: 'account',
  163 + // ---- Tab1:账户管理 ----
  164 + accountQuery: {
  165 + keyword: undefined,
  166 + category: undefined,
  167 + status: undefined
  168 + },
  169 + accountList: [],
  170 + accountLoading: false,
  171 + accountTotal: 0,
  172 + accountListQuery: {
  173 + currentPage: 1,
  174 + pageSize: 20,
  175 + sort: 'desc',
  176 + sidx: ''
115 177 },
116   - // ✅ 获取门店选项(从门店记录)
117   - getssmdOptions(){
118   - previewDataInterface('672484412352365829').then(res => {
119   - this.ssmdOptions = res.data || [];
120   - }).catch(() => {
121   - this.ssmdOptions = [];
122   - });
  178 + accountFormVisible: false,
  179 + categoryOptions: [],
  180 + // ---- Tab2:门店账户授权(原有) ----
  181 + showAll: false,
  182 + query: {
  183 + id: undefined,
  184 + zhmc: undefined,
  185 + ssmd: undefined
123 186 },
124   - initData() {
125   - this.listLoading = true;
126   - let _query = {
127   - ...this.listQuery,
128   - ...this.query
129   - };
130   - let query = {}
131   - for (let key in _query) {
132   - if (Array.isArray(_query[key])) {
133   - query[key] = _query[key].join()
134   - } else {
135   - query[key] = _query[key]
136   - }
137   - }
138   - request({
139   - url: `/api/Extend/WtSkzhb`,
140   - method: 'GET',
141   - data: query
142   - }).then(res => {
143   - this.list = res.data.list
144   - this.total = res.data.pagination.total
145   - this.listLoading = false
146   - })
147   - },
148   - handleDel(id) {
149   - this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
150   - type: 'warning'
151   - }).then(() => {
152   - request({
153   - url: `/api/Extend/WtSkzhb/${id}`,
154   - method: 'DELETE'
155   - }).then(res => {
156   - this.$message({
157   - type: 'success',
158   - message: res.msg,
159   - onClose: () => {
160   - this.initData()
161   - }
162   - });
163   - })
164   - }).catch(() => {
165   - });
166   - },
167   - handleSelectionChange(val) {
168   - const res = val.map(item => item.id)
169   - this.multipleSelection = res
170   - },
171   - handleBatchRemoveDel() {
172   - if (!this.multipleSelection.length) {
173   - this.$message({
174   - type: 'error',
175   - message: '请选择一条数据',
176   - duration: 1500,
177   - })
178   - return
179   - }
180   - const ids = this.multipleSelection
181   - this.$confirm('您确定要删除这些数据吗, 是否继续?', '提示', {
182   - type: 'warning'
183   - }).then(() => {
184   - request({
185   - url: `/api/Extend/WtSkzhb/batchRemove`,
186   - method: 'POST',
187   - data: ids ,
188   - }).then(res => {
189   - this.$message({
190   - type: 'success',
191   - message: res.msg,
192   - onClose: () => {
193   - this.initData()
194   - }
195   - });
196   - })
197   - }).catch(() => { })
198   - },
199   - addOrUpdateHandle(id, isDetail) {
200   - this.formVisible = true
201   - this.$nextTick(() => {
202   - this.$refs.NCCForm.init(id, isDetail)
203   - })
204   - },
205   - exportData() {
206   - this.exportBoxVisible = true
207   - this.$nextTick(() => {
208   - this.$refs.ExportBox.init(this.columnList)
209   - })
210   - },
211   - download(data) {
212   - let query = { ...data, ...this.listQuery, ...this.query }
213   - request({
214   - url: `/api/Extend/WtSkzhb/Actions/Export`,
215   - method: 'GET',
216   - data: query
217   - }).then(res => {
218   - if (!res.data.url) return
219   - window.location.href = this.define.comUrl + res.data.url
220   - this.$refs.ExportBox.visible = false
221   - this.exportBoxVisible = false
222   - })
223   - },
224   - search() {
225   - this.listQuery = {
226   - currentPage: 1,
227   - pageSize: 20,
228   - sort: "desc",
229   - sidx: "",
230   - }
231   - this.initData()
232   - },
233   - refresh(isrRefresh) {
234   - this.formVisible = false
235   - if (isrRefresh) this.reset()
236   - },
237   - reset() {
238   - for (let key in this.query) {
239   - this.query[key] = undefined
240   - }
241   - this.listQuery = {
242   - currentPage: 1,
243   - pageSize: 20,
244   - sort: "desc",
245   - sidx: "",
246   - }
247   - this.initData()
248   - }
  187 + list: [],
  188 + listLoading: true,
  189 + multipleSelection: [],
  190 + total: 0,
  191 + listQuery: {
  192 + currentPage: 1,
  193 + pageSize: 20,
  194 + sort: 'desc',
  195 + sidx: ''
  196 + },
  197 + formVisible: false,
  198 + exportBoxVisible: false,
  199 + columnList: [
  200 + { prop: 'id', label: '账户编号' },
  201 + { prop: 'zhmc', label: '账户名称' },
  202 + { prop: 'ssmd', label: '所属门店' }
  203 + ],
  204 + zhmcOptions: [],
  205 + ssmdOptions: []
  206 + }
  207 + },
  208 + created() {
  209 + this.loadAccountList()
  210 + this.loadCategories()
  211 + },
  212 + methods: {
  213 + handleTabClick(tab) {
  214 + if (tab.name === 'store' && this.list.length === 0) {
  215 + this.initData()
  216 + this.getzhmcOptions()
  217 + this.getssmdOptions()
  218 + }
  219 + },
  220 + // ========== Tab1:账户管理 ==========
  221 + loadAccountList() {
  222 + this.accountLoading = true
  223 + var params = {}
  224 + Object.assign(params, this.accountListQuery)
  225 + if (this.accountQuery.keyword) params.keyword = this.accountQuery.keyword
  226 + if (this.accountQuery.category) params.category = this.accountQuery.category
  227 + if (this.accountQuery.status !== undefined && this.accountQuery.status !== null) {
  228 + params.status = this.accountQuery.status
  229 + }
  230 + getAccountList(params).then(function (res) {
  231 + this.accountList = res.data.list || []
  232 + this.accountTotal = (res.data.pagination && res.data.pagination.total) || 0
  233 + this.accountLoading = false
  234 + }.bind(this)).catch(function () {
  235 + this.accountLoading = false
  236 + }.bind(this))
  237 + },
  238 + loadCategories() {
  239 + getAccountCategories().then(function (res) {
  240 + this.categoryOptions = res.data || []
  241 + }.bind(this)).catch(function () {
  242 + this.categoryOptions = []
  243 + }.bind(this))
  244 + },
  245 + accountSearch() {
  246 + this.accountListQuery.currentPage = 1
  247 + this.loadAccountList()
  248 + },
  249 + accountReset() {
  250 + this.accountQuery = { keyword: undefined, category: undefined, status: undefined }
  251 + this.accountListQuery = { currentPage: 1, pageSize: 20, sort: 'desc', sidx: '' }
  252 + this.loadAccountList()
  253 + },
  254 + openAccountForm(id) {
  255 + this.accountFormVisible = true
  256 + this.$nextTick(function () {
  257 + this.$refs.AccountForm.init(id)
  258 + })
  259 + },
  260 + accountRefresh(isRefresh) {
  261 + this.accountFormVisible = false
  262 + if (isRefresh) {
  263 + this.accountReset()
  264 + this.loadCategories()
  265 + this.getzhmcOptions()
  266 + }
  267 + },
  268 + accountDel(id) {
  269 + this.$confirm('此操作将永久删除该账户, 是否继续?', '提示', { type: 'warning' }).then(function () {
  270 + deleteAccount(id).then(function (res) {
  271 + this.$message({ type: 'success', message: res.msg, onClose: function () { this.loadAccountList() }.bind(this) })
  272 + }.bind(this))
  273 + }.bind(this)).catch(function () {})
  274 + },
  275 + // ========== Tab2:门店账户授权(原有) ==========
  276 + getzhmcOptions() {
  277 + getAccountSelector().then(function (res) {
  278 + this.zhmcOptions = res.data.list || []
  279 + }.bind(this)).catch(function () {
  280 + this.zhmcOptions = []
  281 + }.bind(this))
  282 + },
  283 + getssmdOptions() {
  284 + previewDataInterface('672484412352365829').then(function (res) {
  285 + this.ssmdOptions = res.data || []
  286 + }.bind(this)).catch(function () {
  287 + this.ssmdOptions = []
  288 + }.bind(this))
  289 + },
  290 + initData() {
  291 + this.listLoading = true
  292 + var _query = {}
  293 + Object.assign(_query, this.listQuery, this.query)
  294 + var queryParams = {}
  295 + for (var key in _query) {
  296 + if (Array.isArray(_query[key])) {
  297 + queryParams[key] = _query[key].join()
  298 + } else {
  299 + queryParams[key] = _query[key]
  300 + }
  301 + }
  302 + request({
  303 + url: '/api/Extend/WtSkzhb',
  304 + method: 'GET',
  305 + data: queryParams
  306 + }).then(function (res) {
  307 + this.list = res.data.list
  308 + this.total = res.data.pagination.total
  309 + this.listLoading = false
  310 + }.bind(this))
  311 + },
  312 + handleDel(id) {
  313 + this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', { type: 'warning' }).then(function () {
  314 + request({
  315 + url: '/api/Extend/WtSkzhb/' + id,
  316 + method: 'DELETE'
  317 + }).then(function (res) {
  318 + this.$message({ type: 'success', message: res.msg, onClose: function () { this.initData() }.bind(this) })
  319 + }.bind(this))
  320 + }.bind(this)).catch(function () {})
  321 + },
  322 + handleSelectionChange(val) {
  323 + this.multipleSelection = val.map(function (item) { return item.id })
  324 + },
  325 + handleBatchRemoveDel() {
  326 + if (!this.multipleSelection.length) {
  327 + this.$message({ type: 'error', message: '请选择一条数据', duration: 1500 })
  328 + return
  329 + }
  330 + this.$confirm('您确定要删除这些数据吗, 是否继续?', '提示', { type: 'warning' }).then(function () {
  331 + request({
  332 + url: '/api/Extend/WtSkzhb/batchRemove',
  333 + method: 'POST',
  334 + data: this.multipleSelection
  335 + }).then(function (res) {
  336 + this.$message({ type: 'success', message: res.msg, onClose: function () { this.initData() }.bind(this) })
  337 + }.bind(this))
  338 + }.bind(this)).catch(function () {})
  339 + },
  340 + addOrUpdateHandle(id, isDetail) {
  341 + this.formVisible = true
  342 + this.$nextTick(function () {
  343 + this.$refs.NCCForm.init(id, isDetail)
  344 + })
  345 + },
  346 + exportData() {
  347 + this.exportBoxVisible = true
  348 + this.$nextTick(function () {
  349 + this.$refs.ExportBox.init(this.columnList)
  350 + })
  351 + },
  352 + download(data) {
  353 + var downloadQuery = {}
  354 + Object.assign(downloadQuery, data, this.listQuery, this.query)
  355 + request({
  356 + url: '/api/Extend/WtSkzhb/Actions/Export',
  357 + method: 'GET',
  358 + data: downloadQuery
  359 + }).then(function (res) {
  360 + if (!res.data.url) return
  361 + window.location.href = this.define.comUrl + res.data.url
  362 + this.$refs.ExportBox.visible = false
  363 + this.exportBoxVisible = false
  364 + }.bind(this))
  365 + },
  366 + search() {
  367 + this.listQuery = { currentPage: 1, pageSize: 20, sort: 'desc', sidx: '' }
  368 + this.initData()
  369 + },
  370 + refresh(isRefresh) {
  371 + this.formVisible = false
  372 + if (isRefresh) this.reset()
  373 + },
  374 + reset() {
  375 + for (var key in this.query) {
  376 + this.query[key] = undefined
  377 + }
  378 + this.listQuery = { currentPage: 1, pageSize: 20, sort: 'desc', sidx: '' }
  379 + this.initData()
249 380 }
250   - }
251   -</script>
252 381 \ No newline at end of file
  382 + }
  383 +}
  384 +</script>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtSwdd/Form.vue
... ... @@ -159,8 +159,8 @@
159 159 </template>
160 160 <script>
161 161 import request from '@/utils/request'
162   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
163 162 import { previewDataInterface } from '@/api/systemData/dataInterface'
  163 + import { getAccountSelector } from '@/api/extend/wtAccount'
164 164 export default {
165 165 components: {},
166 166 props: [],
... ... @@ -235,7 +235,7 @@
235 235 });
236 236 },
237 237 getskzhOptions(){
238   - getDictionaryDataSelector('681761709836207365').then(res => {
  238 + getAccountSelector().then(res => {
239 239 this.skzhOptions = res.data.list
240 240 });
241 241 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtSwdd/index.vue
... ... @@ -132,10 +132,10 @@
132 132 </template>
133 133 <script>
134 134 import request from '@/utils/request'
135   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
136 135 import NCCForm from './Form'
137 136 import ExportBox from './ExportBox'
138 137 import { previewDataInterface } from '@/api/systemData/dataInterface'
  138 + import { getAccountSelector } from '@/api/extend/wtAccount'
139 139 export default {
140 140 components: { NCCForm, ExportBox },
141 141 data() {
... ... @@ -205,7 +205,7 @@
205 205 });
206 206 },
207 207 getskzhOptions(){
208   - getDictionaryDataSelector('681761709836207365').then(res => {
  208 + getAccountSelector().then(res => {
209 209 this.skzhOptions = res.data.list
210 210 });
211 211 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtTjdbd/Form.vue
... ... @@ -251,10 +251,10 @@
251 251 </template>
252 252 <script>
253 253 import request from '@/utils/request'
254   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
255 254 import { previewDataInterface } from '@/api/systemData/dataInterface'
256 255 import BarcodeSelect from '../wtCgrkd/BarcodeSelect.vue'
257 256 import SerialNumberSelect from './SerialNumberSelect.vue'
  257 + import { getAccountSelector } from '@/api/extend/wtAccount'
258 258 export default {
259 259 components: { BarcodeSelect, SerialNumberSelect },
260 260 props: [],
... ... @@ -605,7 +605,7 @@
605 605 });
606 606 },
607 607 getskzhOptions(){
608   - getDictionaryDataSelector('681761709836207365').then(res => {
  608 + getAccountSelector().then(res => {
609 609 this.skzhOptions = res.data.list
610 610 });
611 611 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtTjdbd/index.vue
... ... @@ -177,12 +177,12 @@
177 177 </template>
178 178 <script>
179 179 import request from '@/utils/request'
180   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
181 180 import NCCForm from './Form'
182 181 import DetailView from './detail-view'
183 182 import ExportBox from './ExportBox'
184 183 import { previewDataInterface } from '@/api/systemData/dataInterface'
185 184 import { promptApprovalRemark, postApproveGeneric, postRejectGeneric } from '@/utils/wtRejectApproval'
  185 + import { getAccountSelector } from '@/api/extend/wtAccount'
186 186 export default {
187 187 components: { NCCForm, DetailView, ExportBox },
188 188 data() {
... ... @@ -333,7 +333,7 @@
333 333 });
334 334 },
335 335 getskzhOptions(){
336   - getDictionaryDataSelector('681761709836207365').then(res => {
  336 + getAccountSelector().then(res => {
337 337 this.skzhOptions = res.data.list
338 338 });
339 339 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXlh/index.vue
... ... @@ -33,6 +33,7 @@
33 33 <el-col :span="6">
34 34 <el-form-item>
35 35 <el-button type="primary" icon="el-icon-search" @click="search()">查询</el-button>
  36 + <el-button type="success" plain icon="el-icon-sort" @click="openSerialTrace">序列号流水</el-button>
36 37 <el-button icon="el-icon-refresh-right" @click="reset()">重置</el-button>
37 38 <el-button type="text" icon="el-icon-arrow-down" @click="showAll=true" v-if="!showAll">展开</el-button>
38 39 <el-button type="text" icon="el-icon-arrow-up" @click="showAll=false" v-else>收起</el-button>
... ... @@ -43,9 +44,7 @@
43 44 <div class="NCC-common-layout-main NCC-flex-main">
44 45 <div class="NCC-common-head">
45 46 <div>
46   - <el-button type="primary" icon="el-icon-plus" @click="addOrUpdateHandle()">新增</el-button>
47 47 <el-button type="text" icon="el-icon-download" @click="exportData()">导出</el-button>
48   - <el-button type="text" icon="el-icon-delete" @click="handleBatchRemoveDel()">批量删除</el-button>
49 48 </div>
50 49 <div class="NCC-common-head-right">
51 50 <el-tooltip effect="dark" content="刷新" placement="top">
... ... @@ -54,7 +53,7 @@
54 53 <screenfull isContainer />
55 54 </div>
56 55 </div>
57   - <NCC-table v-loading="listLoading" :data="list" has-c @selection-change="handleSelectionChange">
  56 + <NCC-table v-loading="listLoading" :data="list">
58 57 <el-table-column prop="xlh" label="序列号" align="left" />
59 58 <el-table-column prop="spbh" label="商品编号" align="left" />
60 59 <el-table-column prop="spmc" label="商品名称" align="left" />
... ... @@ -65,29 +64,20 @@
65 64 <el-table-column prop="djlx" label="单据类型" align="left" />
66 65 <el-table-column prop="zt" label="状态" align="left" />
67 66 <el-table-column prop="djrq" label="单据日期" :formatter="ncc.tableDateFormat" align="left" />
68   -
69   - <el-table-column label="操作" fixed="right" width="100">
70   - <template slot-scope="scope">
71   - <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
72   - <el-button type="text" @click="handleDel(scope.row.id)" class="NCC-table-delBtn" >删除</el-button>
73   - </template>
74   - </el-table-column>
75 67 </NCC-table>
76 68 <pagination :total="total" :page.sync="listQuery.currentPage" :limit.sync="listQuery.pageSize" @pagination="initData" />
77 69 </div>
78 70 </div>
79   - <NCC-Form v-if="formVisible" ref="NCCForm" @refresh="refresh" />
80 71 <ExportBox v-if="exportBoxVisible" ref="ExportBox" @download="download" />
  72 + <serial-trace-dialog :visible.sync="traceVisible" :xlh="traceXlh" />
81 73 </div>
82 74 </template>
83 75 <script>
84 76 import request from '@/utils/request'
85   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
86   - import NCCForm from './Form'
87 77 import ExportBox from './ExportBox'
88   - import { previewDataInterface } from '@/api/systemData/dataInterface'
  78 + import SerialTraceDialog from './serial-trace-dialog.vue'
89 79 export default {
90   - components: { NCCForm, ExportBox },
  80 + components: { ExportBox, SerialTraceDialog },
91 81 data() {
92 82 return {
93 83 showAll: false,
... ... @@ -100,15 +90,16 @@
100 90 },
101 91 list: [],
102 92 listLoading: true,
103   - multipleSelection: [], total: 0,
  93 + total: 0,
104 94 listQuery: {
105 95 currentPage: 1,
106 96 pageSize: 20,
107 97 sort: "desc",
108 98 sidx: "",
109 99 },
110   - formVisible: false,
111 100 exportBoxVisible: false,
  101 + traceVisible: false,
  102 + traceXlh: '',
112 103 columnList: [
113 104 { prop: 'xlh', label: '序列号' },
114 105 { prop: 'spbh', label: '商品编号' },
... ... @@ -147,63 +138,6 @@
147 138 this.listLoading = false
148 139 })
149 140 },
150   - handleDel(id) {
151   - this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
152   - type: 'warning'
153   - }).then(() => {
154   - request({
155   - url: `/api/Extend/WtXlh/${id}`,
156   - method: 'DELETE'
157   - }).then(res => {
158   - this.$message({
159   - type: 'success',
160   - message: res.msg,
161   - onClose: () => {
162   - this.initData()
163   - }
164   - });
165   - })
166   - }).catch(() => {
167   - });
168   - },
169   - handleSelectionChange(val) {
170   - const res = val.map(item => item.id)
171   - this.multipleSelection = res
172   - },
173   - handleBatchRemoveDel() {
174   - if (!this.multipleSelection.length) {
175   - this.$message({
176   - type: 'error',
177   - message: '请选择一条数据',
178   - duration: 1500,
179   - })
180   - return
181   - }
182   - const ids = this.multipleSelection
183   - this.$confirm('您确定要删除这些数据吗, 是否继续?', '提示', {
184   - type: 'warning'
185   - }).then(() => {
186   - request({
187   - url: `/api/Extend/WtXlh/batchRemove`,
188   - method: 'POST',
189   - data: ids ,
190   - }).then(res => {
191   - this.$message({
192   - type: 'success',
193   - message: res.msg,
194   - onClose: () => {
195   - this.initData()
196   - }
197   - });
198   - })
199   - }).catch(() => { })
200   - },
201   - addOrUpdateHandle(id, isDetail) {
202   - this.formVisible = true
203   - this.$nextTick(() => {
204   - this.$refs.NCCForm.init(id, isDetail)
205   - })
206   - },
207 141 exportData() {
208 142 this.exportBoxVisible = true
209 143 this.$nextTick(() => {
... ... @@ -232,8 +166,16 @@
232 166 }
233 167 this.initData()
234 168 },
  169 + openSerialTrace() {
  170 + const x = (this.query.xlh != null ? String(this.query.xlh) : '').trim()
  171 + if (!x) {
  172 + this.$message.warning('请先在「序列号」中输入要查询的完整序列号')
  173 + return
  174 + }
  175 + this.traceXlh = x
  176 + this.traceVisible = true
  177 + },
235 178 refresh(isrRefresh) {
236   - this.formVisible = false
237 179 if (isrRefresh) this.reset()
238 180 },
239 181 reset() {
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXlh/serial-trace-dialog.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + title="序列号单据流水"
  4 + :visible.sync="innerVisible"
  5 + width="900px"
  6 + append-to-body
  7 + class="NCC-dialog NCC-dialog_center"
  8 + @close="onClose"
  9 + >
  10 + <div v-if="xlhKey" class="trace-tip">
  11 + 序列号:<strong>{{ xlhKey }}</strong>(按单据日期从早到晚排列,含出货与退货等)
  12 + </div>
  13 + <el-table
  14 + v-loading="loading"
  15 + :data="list"
  16 + size="small"
  17 + border
  18 + style="width: 100%; margin-top: 12px;"
  19 + >
  20 + <el-table-column prop="djrq" label="单据日期" width="168" :formatter="formatDjrq" show-overflow-tooltip />
  21 + <el-table-column prop="djlx" label="单据类型" width="140" show-overflow-tooltip />
  22 + <el-table-column prop="djbh" label="单据编号" min-width="140" show-overflow-tooltip />
  23 + <el-table-column prop="zt" label="状态" width="100" show-overflow-tooltip />
  24 + <el-table-column prop="spmc" label="商品名称" min-width="160" show-overflow-tooltip />
  25 + </el-table>
  26 + <el-pagination
  27 + v-if="total > pageSize"
  28 + style="margin-top: 12px;"
  29 + background
  30 + layout="total, prev, pager, next"
  31 + :total="total"
  32 + :page-size="pageSize"
  33 + :current-page.sync="page"
  34 + @current-change="loadData"
  35 + />
  36 + <span slot="footer" class="dialog-footer">
  37 + <el-button @click="innerVisible = false">关 闭</el-button>
  38 + </span>
  39 + </el-dialog>
  40 +</template>
  41 +
  42 +<script>
  43 +import request from '@/utils/request'
  44 +import ncc from '@/utils/ncc'
  45 +
  46 +export default {
  47 + name: 'SerialTraceDialog',
  48 + props: {
  49 + visible: {
  50 + type: Boolean,
  51 + default: false
  52 + },
  53 + xlh: {
  54 + type: String,
  55 + default: ''
  56 + }
  57 + },
  58 + data() {
  59 + return {
  60 + innerVisible: false,
  61 + list: [],
  62 + loading: false,
  63 + total: 0,
  64 + page: 1,
  65 + pageSize: 100,
  66 + xlhKey: ''
  67 + }
  68 + },
  69 + watch: {
  70 + visible(v) {
  71 + this.innerVisible = v
  72 + if (v) {
  73 + this.xlhKey = (this.xlh || '').trim()
  74 + this.page = 1
  75 + this.loadData()
  76 + }
  77 + },
  78 + innerVisible(v) {
  79 + if (!v) {
  80 + this.$emit('update:visible', false)
  81 + }
  82 + }
  83 + },
  84 + methods: {
  85 + formatDjrq(row, column, cellValue) {
  86 + return ncc.tableDateFormat(row, column, cellValue)
  87 + },
  88 + onClose() {
  89 + this.$emit('update:visible', false)
  90 + },
  91 + loadData() {
  92 + if (!this.xlhKey) {
  93 + this.list = []
  94 + this.total = 0
  95 + return
  96 + }
  97 + this.loading = true
  98 + request({
  99 + url: '/api/Extend/WtXlh/SerialTrace',
  100 + method: 'GET',
  101 + data: {
  102 + xlh: this.xlhKey,
  103 + currentPage: this.page,
  104 + pageSize: this.pageSize
  105 + }
  106 + })
  107 + .then(res => {
  108 + this.list = res.data.list || []
  109 + this.total = (res.data.pagination && res.data.pagination.total) || 0
  110 + })
  111 + .finally(() => {
  112 + this.loading = false
  113 + })
  114 + }
  115 + }
  116 +}
  117 +</script>
  118 +
  119 +<style scoped>
  120 +.trace-tip {
  121 + font-size: 13px;
  122 + color: #606266;
  123 +}
  124 +</style>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXndd/Form.vue
... ... @@ -159,8 +159,8 @@
159 159 </template>
160 160 <script>
161 161 import request from '@/utils/request'
162   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
163 162 import { previewDataInterface } from '@/api/systemData/dataInterface'
  163 + import { getAccountSelector } from '@/api/extend/wtAccount'
164 164 export default {
165 165 components: {},
166 166 props: [],
... ... @@ -235,7 +235,7 @@
235 235 });
236 236 },
237 237 getskzhOptions(){
238   - getDictionaryDataSelector('681761709836207365').then(res => {
  238 + getAccountSelector().then(res => {
239 239 this.skzhOptions = res.data.list
240 240 });
241 241 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXndd/index.vue
... ... @@ -132,10 +132,10 @@
132 132 </template>
133 133 <script>
134 134 import request from '@/utils/request'
135   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
136 135 import NCCForm from './Form'
137 136 import ExportBox from './ExportBox'
138 137 import { previewDataInterface } from '@/api/systemData/dataInterface'
  138 + import { getAccountSelector } from '@/api/extend/wtAccount'
139 139 export default {
140 140 components: { NCCForm, ExportBox },
141 141 data() {
... ... @@ -205,7 +205,7 @@
205 205 });
206 206 },
207 207 getskzhOptions(){
208   - getDictionaryDataSelector('681761709836207365').then(res => {
  208 + getAccountSelector().then(res => {
209 209 this.skzhOptions = res.data.list
210 210 });
211 211 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsckd/Form.vue
... ... @@ -147,16 +147,6 @@
147 147 <el-input v-model="scope.row.je" placeholder="请输入" clearable readonly></el-input>
148 148 </template>
149 149 </el-table-column>
150   - <el-table-column prop="cbdj" label="成本单价" width="100" align="right">
151   - <template slot-scope="scope">
152   - <span class="cost-cell">{{ formatCostCell(scope.row.cbdj) }}</span>
153   - </template>
154   - </el-table-column>
155   - <el-table-column prop="cbje" label="成本金额" width="100" align="right">
156   - <template slot-scope="scope">
157   - <span class="cost-cell">{{ formatCostCell(scope.row.cbje) }}</span>
158   - </template>
159   - </el-table-column>
160 150 <el-table-column prop="description" label="备注">
161 151 <template slot-scope="scope">
162 152 <el-input v-model="scope.row.description" placeholder="请输入备注" clearable></el-input>
... ... @@ -220,19 +210,14 @@
220 210 </div>
221 211 </el-form-item>
222 212 </el-col>
223   - <el-col :span="8">
  213 + <el-col :span="12">
224 214 <el-form-item label="收款账户" prop="skzh">
225 215 <el-select v-model="dataForm.skzh" placeholder="请选择" clearable :style='{"width":"100%"}' filterable >
226 216 <el-option v-for="(item, index) in skzhOptions" :key="index" :label="item.fullName" :value="item.id" ></el-option>
227 217 </el-select>
228 218 </el-form-item>
229 219 </el-col>
230   - <el-col :span="8">
231   - <el-form-item label="出库成本合计">
232   - <el-input :value="displayOutboundCostTotalText" placeholder="按明细成本汇总" readonly :style='{"width":"100%"}' />
233   - </el-form-item>
234   - </el-col>
235   - <el-col :span="8">
  220 + <el-col :span="12">
236 221 <el-form-item label="收款金额" prop="skje">
237 222 <el-input v-model="dataForm.skje" placeholder="自动计算" clearable :style='{"width":"100%"}' readonly>
238 223 </el-input>
... ... @@ -299,10 +284,10 @@
299 284 </template>
300 285 <script>
301 286 import request from '@/utils/request'
302   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
303 287 import { previewDataInterface } from '@/api/systemData/dataInterface'
304 288 import BarcodeSelect from '../wtCgrkd/BarcodeSelect.vue'
305 289 import SerialNumberSelect from './SerialNumberSelect.vue'
  290 + import { getAccountSelector } from '@/api/extend/wtAccount'
306 291 export default {
307 292 components: { BarcodeSelect, SerialNumberSelect },
308 293 props: [],
... ... @@ -339,8 +324,6 @@
339 324 },
340 325 rules: {
341 326 },
342   - // 当前出库门店下各商品成本预览(下拉展示用,key=商品F_Id)
343   - productCostPreviewMap: {},
344 327 cjckOptions : [],
345 328 rkckOptions : [],
346 329 khOptions : [],
... ... @@ -364,19 +347,6 @@
364 347 totalJe() {
365 348 return (this.dataForm.wtXsckdMxList || []).reduce((sum, row) => sum + (parseFloat(row.je) || 0), 0)
366 349 },
367   - // 详情页优先用主表 cbje;新建/编辑按明细成本金额汇总
368   - displayOutboundCostTotal() {
369   - if (this.isDetail && this.dataForm.cbje != null && this.dataForm.cbje !== '') {
370   - const m = parseFloat(this.dataForm.cbje)
371   - if (!isNaN(m)) return m
372   - }
373   - return (this.dataForm.wtXsckdMxList || []).reduce((s, r) => s + (parseFloat(r.cbje) || 0), 0)
374   - },
375   - displayOutboundCostTotalText() {
376   - const v = this.displayOutboundCostTotal
377   - return (typeof v === 'number' && !isNaN(v)) ? v.toFixed(2) : '0.00'
378   - },
379   -
380 350 },
381 351 watch: {},
382 352 created() {
... ... @@ -643,7 +613,7 @@
643 613 });
644 614 },
645 615 getskzhOptions(){
646   - getDictionaryDataSelector('681761709836207365').then(res => {
  616 + getAccountSelector().then(res => {
647 617 this.skzhOptions = res.data.list
648 618 });
649 619 },
... ... @@ -723,7 +693,6 @@
723 693 _this.restoreSerialNumbers();
724 694 // 编辑时自动获取所有明细行的账面库存
725 695 _this.$nextTick(() => {
726   - _this.loadProductCostPreviewMap();
727 696 _this.dataForm.wtXsckdMxList.forEach(row => {
728 697 if (row.spbh && row.ckck) {
729 698 _this.getStockQuantity(row);
... ... @@ -745,7 +714,6 @@
745 714 if (res.data.mrwldw) _this.dataForm.kh = res.data.mrwldw
746 715 if (res.data.mrskzh) _this.dataForm.skzh = res.data.mrskzh
747 716 }
748   - _this.loadProductCostPreviewMap();
749 717 }).catch(() => {})
750 718 }
751 719 })
... ... @@ -1117,7 +1085,12 @@
1117 1085 if (!this.currentBarcodeRow.ckck && this.dataForm.cjck) {
1118 1086 this.currentBarcodeRow.ckck = this.dataForm.cjck
1119 1087 }
1120   - this.fetchRowCost(this.currentBarcodeRow)
  1088 + // 与下拉选商品一致:拉序列号类型、账面库存(销售单价仍手工录入)
  1089 + this.$nextTick(() => {
  1090 + if (this.currentBarcodeRow && this.currentBarcodeRow.spbh) {
  1091 + this.handleProductChange(this.currentBarcodeRow)
  1092 + }
  1093 + })
1121 1094 }
1122 1095 },
1123 1096  
... ... @@ -1154,7 +1127,6 @@
1154 1127 if (currentRow.dj) {
1155 1128 currentRow.je = (parseFloat(currentRow.sl) * parseFloat(currentRow.dj)).toFixed(2)
1156 1129 }
1157   - this.updateRowCostAmount(currentRow)
1158 1130 // 更新总收款金额
1159 1131 this.calculateTotalAmount();
1160 1132  
... ... @@ -1165,7 +1137,6 @@
1165 1137 const sl = parseFloat(row.sl) || 0;
1166 1138 const dj = parseFloat(row.dj) || 0;
1167 1139 row.je = (sl * dj).toFixed(2);
1168   - this.updateRowCostAmount(row)
1169 1140 // 自动计算总收款金额
1170 1141 this.calculateTotalAmount();
1171 1142 // 检查数量与序列号数量是否一致
... ... @@ -1187,12 +1158,10 @@
1187 1158 }
1188 1159 // 同步更新所有明细行的出库仓库
1189 1160 this.syncDetailWarehouses();
1190   - this.loadProductCostPreviewMap()
1191   - // 更新所有明细行的库存与成本预览
  1161 + // 更新所有明细行的账面库存
1192 1162 this.dataForm.wtXsckdMxList.forEach(row => {
1193 1163 if (row.spbh) {
1194 1164 this.getStockQuantity(row);
1195   - this.fetchRowCost(row);
1196 1165 }
1197 1166 });
1198 1167 },
... ... @@ -1561,12 +1530,12 @@
1561 1530 sums[index] = '合计';
1562 1531 return;
1563 1532 }
1564   - if (['kucun', 'sl', 'je', 'cbje'].includes(column.property)) {
  1533 + if (['kucun', 'sl', 'je'].includes(column.property)) {
1565 1534 const t = data.reduce((total, row) => {
1566 1535 const value = parseFloat(row[column.property]);
1567 1536 return total + (isNaN(value) ? 0 : value);
1568 1537 }, 0);
1569   - sums[index] = (column.property === 'cbje' || column.property === 'je') ? t.toFixed(2) : t;
  1538 + sums[index] = column.property === 'je' ? t.toFixed(2) : t;
1570 1539 } else {
1571 1540 sums[index] = '';
1572 1541 }
... ... @@ -1578,99 +1547,24 @@
1578 1547 const label = (option.label || '').toLowerCase();
1579 1548 return label.includes(query.toLowerCase());
1580 1549 },
1581   - // 成本/库存接口使用的门店或仓库ID
1582   - costContextCk() {
1583   - if (this.dataForm.cjckId != null && this.dataForm.cjckId !== '') {
1584   - return this.dataForm.cjckId
1585   - }
1586   - return this.dataForm.cjck
1587   - },
1588   - formatCostCell(val) {
1589   - if (val == null || val === '') return '无'
1590   - const n = parseFloat(val)
1591   - if (isNaN(n)) return '无'
1592   - return n.toFixed(2)
1593   - },
1594 1550 getSpOptionLabel(item) {
1595 1551 const base = ((item.spbm || '') + ' ' + (item.F_Spmc || '')).trim()
1596   - // const c = this.productCostPreviewMap[item.F_Id]
1597   - // if (c != null && c !== '' && !isNaN(parseFloat(c))) {
1598   - // return base + ' (成本¥' + parseFloat(c).toFixed(2) + ')'
1599   - // }
1600   - // if (!this.costContextCk()) {
1601   - // return base + ' (选仓库后显示成本)'
1602   - // }
1603 1552 return base
1604 1553 },
1605   - async loadProductCostPreviewMap() {
1606   - const ck = this.costContextCk()
1607   - if (!ck) {
1608   - this.productCostPreviewMap = {}
1609   - return
1610   - }
1611   - try {
1612   - const res = await request({
1613   - url: '/api/Extend/WtTjd/Actions/GetCostPreviewForStore',
1614   - method: 'get',
1615   - data: { ck }
1616   - })
1617   - let items = res.data
1618   - if (items && items.items) items = items.items
1619   - else if (res.items) items = res.items
1620   - const map = {}
1621   - ;(Array.isArray(items) ? items : []).forEach(x => {
1622   - if (x && x.spbh != null && map[x.spbh] == null) {
1623   - map[x.spbh] = parseFloat(x.cbj) || 0
1624   - }
1625   - })
1626   - this.productCostPreviewMap = map
1627   - } catch (e) {
1628   - console.warn('loadProductCostPreviewMap failed', e)
1629   - this.productCostPreviewMap = {}
1630   - }
1631   - },
1632   - async fetchRowCost(row) {
1633   - const ck = row.ckck || this.costContextCk()
1634   - if (!row.spbh || !ck) {
1635   - this.$set(row, 'cbdj', undefined)
1636   - this.$set(row, 'cbje', undefined)
1637   - return
1638   - }
1639   - try {
1640   - const res = await request({
1641   - url: '/api/Extend/WtTjd/Actions/GetCost',
1642   - method: 'get',
1643   - data: { spbh: row.spbh, ck }
1644   - })
1645   - let payload = res.data
1646   - if (payload && typeof payload.cbj === 'undefined' && res.data && res.data.data) {
1647   - payload = res.data.data
1648   - }
1649   - const cbj = parseFloat(payload && payload.cbj != null ? payload.cbj : 0) || 0
1650   - this.$set(row, 'cbdj', cbj)
1651   - this.updateRowCostAmount(row)
1652   - } catch (e) {
1653   - this.$set(row, 'cbdj', 0)
1654   - this.updateRowCostAmount(row)
1655   - }
1656   - },
1657   - updateRowCostAmount(row) {
1658   - const sl = parseFloat(row.sl) || 0
1659   - const cbdj = parseFloat(row.cbdj) || 0
1660   - this.$set(row, 'cbje', (cbdj * sl).toFixed(2))
1661   - },
1662 1554 handleProductChange(row) {
1663 1555 if (!row.spbh) {
1664 1556 this.$set(row, 'cbdj', undefined)
1665 1557 this.$set(row, 'cbje', undefined)
  1558 + this.$set(row, 'dj', undefined)
  1559 + this.$set(row, 'je', undefined)
  1560 + this.$set(row, 'spmc', '')
1666 1561 return
1667 1562 }
1668 1563 // 选中商品后可自动回填商品名称等信息
1669 1564 const product = this.spbhOptions.find(item => item.F_Id === row.spbh);
1670 1565 if (product) {
1671 1566 row.spmc = product.F_Spmc || '';
1672   - // ✅ 从商品主档回填单价(零售价)
1673   - row.dj = product.F_Lsj || 0;
  1567 + // 销售单价由用户手工录入,不从商品主档自动带出
1674 1568 // 选中商品后,立即加载商品信息(如序列号类型)
1675 1569 this.getProductInfo(row.spbh).then(productInfo => {
1676 1570 // 触发当前行的响应式刷新
... ... @@ -1697,11 +1591,9 @@
1697 1591 return;
1698 1592 }
1699 1593  
1700   - // 如果已选择出库仓库,自动获取库存与成本
  1594 + // 如果已选择出库仓库,自动获取账面库存
1701 1595 console.log('开始获取库存...');
1702   - this.getStockQuantity(row).finally(() => {
1703   - this.fetchRowCost(row)
1704   - });
  1596 + this.getStockQuantity(row)
1705 1597 }
1706 1598 },
1707 1599 handleProductQuery(val, scope) {
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsckd/detail-view.vue
... ... @@ -134,11 +134,6 @@
134 134 <span class="cell-nowrap mx-cell__money">{{ formatMoneyCol(scope.row.je) }}</span>
135 135 </template>
136 136 </el-table-column>
137   - <el-table-column prop="cbje" label="成本" width="96" align="right">
138   - <template slot-scope="scope">
139   - <span class="cell-nowrap">{{ formatMoneyCol(scope.row.cbje) }}</span>
140   - </template>
141   - </el-table-column>
142 137 <el-table-column label="序列号" min-width="168">
143 138 <template slot-scope="scope">
144 139 <div v-if="scope.row.selectedSerialNumbers && scope.row.selectedSerialNumbers.length" class="sn-tags">
... ... @@ -181,12 +176,6 @@
181 176 {{ displayDiscountAmount }}
182 177 </span>
183 178 </el-descriptions-item>
184   - <el-descriptions-item label="出库成本">
185   - <span class="cell-nowrap">
186   - <i class="el-icon-s-grid desc-icon desc-icon--info" />
187   - {{ formatMoneyCol(detail.cbje) }}
188   - </span>
189   - </el-descriptions-item>
190 179 <el-descriptions-item label="制单人">
191 180 <span class="cell-nowrap">
192 181 <i class="el-icon-edit-outline desc-icon desc-icon--muted" />
... ... @@ -310,9 +299,9 @@
310 299  
311 300 <script>
312 301 import request from '@/utils/request'
313   -import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
314 302 import { previewDataInterface } from '@/api/systemData/dataInterface'
315 303 import { dynamicText } from '@/filters'
  304 +import { getAccountSelector } from '@/api/extend/wtAccount'
316 305 import {
317 306 formatWtSkzhDisplay,
318 307 resolveSkzhDictionaryLabel,
... ... @@ -473,12 +462,23 @@ export default {
473 462 },
474 463 formatDjrq(ts) {
475 464 if (ts == null || ts === '') return '无'
476   - const d = new Date(typeof ts === 'number' ? ts : Number(ts))
  465 + const raw = typeof ts === 'string' ? ts.trim() : ts
  466 + if (raw === '') return '无'
  467 + let d
  468 + if (typeof raw === 'number') {
  469 + d = new Date(raw)
  470 + } else {
  471 + const n = Number(raw)
  472 + d = !isNaN(n) ? new Date(n) : new Date(String(raw).replace(/-/g, '/'))
  473 + }
477 474 if (isNaN(d.getTime())) return '无'
478 475 const y = d.getFullYear()
479 476 const m = String(d.getMonth() + 1).padStart(2, '0')
480 477 const day = String(d.getDate()).padStart(2, '0')
481   - return `${y}-${m}-${day}`
  478 + const h = String(d.getHours()).padStart(2, '0')
  479 + const mi = String(d.getMinutes()).padStart(2, '0')
  480 + const s = String(d.getSeconds()).padStart(2, '0')
  481 + return `${y}-${m}-${day} ${h}:${mi}:${s}`
482 482 },
483 483 getSummaries(param) {
484 484 const { columns, data } = param
... ... @@ -494,10 +494,6 @@ export default {
494 494 sums[index] = data
495 495 .reduce((t, row) => t + (parseFloat(row.je) || 0), 0)
496 496 .toFixed(2)
497   - } else if (column.property === 'cbje') {
498   - sums[index] = data
499   - .reduce((t, row) => t + (parseFloat(row.cbje) || 0), 0)
500   - .toFixed(2)
501 497 } else {
502 498 sums[index] = ''
503 499 }
... ... @@ -539,7 +535,7 @@ export default {
539 535 previewDataInterface('681758216954053893').then(res => {
540 536 this.cjckOptions = res.data || []
541 537 })
542   - getDictionaryDataSelector('681761709836207365').then(res => {
  538 + getAccountSelector().then(res => {
543 539 const d = res.data
544 540 this.skzhOptions =
545 541 d && Array.isArray(d.list) ? d.list : Array.isArray(d) ? d : []
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsckd/index.vue
... ... @@ -140,15 +140,9 @@
140 140 <el-table-column label="优惠金额" align="right" min-width="96" show-overflow-tooltip>
141 141 <template slot-scope="scope">{{ getDisplayDiscountAmount(scope.row) }}</template>
142 142 </el-table-column>
143   - <el-table-column label="出库成本" align="right" min-width="96" show-overflow-tooltip>
144   - <template slot-scope="scope">{{ getDisplayOutboundCost(scope.row) }}</template>
145   - </el-table-column>
146 143 <el-table-column label="收款账户" prop="skzh" align="left" min-width="120" show-overflow-tooltip>
147 144 <template slot-scope="scope">{{ displayText(formatSkzhRow(scope.row)) }}</template>
148 145 </el-table-column>
149   - <el-table-column prop="zdr" label="制单人" align="left" min-width="88" show-overflow-tooltip>
150   - <template slot-scope="scope">{{ displayText(scope.row.zdr) }}</template>
151   - </el-table-column>
152 146 <el-table-column prop="shr" label="审核人" align="left" min-width="88" show-overflow-tooltip>
153 147 <template slot-scope="scope">{{ displayText(scope.row.shr) }}</template>
154 148 </el-table-column>
... ... @@ -210,7 +204,6 @@
210 204 </template>
211 205 <script>
212 206 import request from '@/utils/request'
213   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
214 207 import NCCForm from './Form'
215 208 import DetailView from './detail-view'
216 209 import ExportBox from './ExportBox'
... ... @@ -218,6 +211,7 @@
218 211 import { promptApprovalRemark, postApproveSalesOutbound, postRejectGeneric } from '@/utils/wtRejectApproval'
219 212 import { formatWtSkzhDisplay } from '@/utils/wtComboSkzhDisplay'
220 213 import { dynamicText } from '@/filters'
  214 + import { getAccountSelector } from '@/api/extend/wtAccount'
221 215 export default {
222 216 components: { NCCForm, DetailView, ExportBox },
223 217 data() {
... ... @@ -260,7 +254,6 @@
260 254 { prop: 'skzh', label: '收款账户' },
261 255 { prop: 'skje', label: '收款金额' },
262 256 { prop: 'ysje', label: '优惠金额' },
263   - { prop: 'zdr', label: '制单人' },
264 257 { prop: 'shr', label: '审核人' },
265 258 { prop: 'gzr', label: '过账人' },
266 259 { prop: 'bz', label: '备注' },
... ... @@ -404,11 +397,6 @@
404 397 }
405 398 return (row.skje != null && row.skje !== '') ? parseFloat(row.skje).toFixed(2) : '0.00';
406 399 },
407   - // ✅ 出库成本:使用主表字段 cbje,空值按金额风格显示为 0.00
408   - getDisplayOutboundCost(row) {
409   - const val = parseFloat(row.cbje);
410   - return isNaN(val) ? '0.00' : val.toFixed(2);
411   - },
412 400 getcjckOptions(){
413 401 previewDataInterface('681758216954053893').then(res => {
414 402 this.cjckOptions = res.data
... ... @@ -420,7 +408,7 @@
420 408 });
421 409 },
422 410 getskzhOptions(){
423   - getDictionaryDataSelector('681761709836207365').then(res => {
  411 + getAccountSelector().then(res => {
424 412 this.skzhOptions = res.data.list
425 413 });
426 414 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsthd/Form.vue
... ... @@ -250,10 +250,10 @@
250 250 </template>
251 251 <script>
252 252 import request from '@/utils/request'
253   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
254 253 import { previewDataInterface } from '@/api/systemData/dataInterface'
255 254 import SerialNumberSelect from '../wtXsckd/SerialNumberSelect.vue'
256 255 import ShipmentOrderSelect from '../wtXswtdxjsd/ShipmentOrderSelect.vue'
  256 + import { getAccountSelector } from '@/api/extend/wtAccount'
257 257 export default {
258 258 components: { SerialNumberSelect, ShipmentOrderSelect },
259 259 props: [],
... ... @@ -345,7 +345,7 @@
345 345 });
346 346 },
347 347 getskzhOptions(){
348   - getDictionaryDataSelector('681761709836207365').then(res => {
  348 + getAccountSelector().then(res => {
349 349 this.skzhOptions = res.data.list
350 350 });
351 351 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsthd/detail-view.vue
... ... @@ -203,10 +203,10 @@
203 203 <script>
204 204 import request from '@/utils/request'
205 205 import { getUserInfoList } from '@/api/permission/user'
206   -import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
207 206 import { previewDataInterface } from '@/api/systemData/dataInterface'
208 207 import { dynamicText } from '@/filters'
209 208 import XsckdDetailView from '../wtXsckd/detail-view'
  209 +import { getAccountSelector } from '@/api/extend/wtAccount'
210 210  
211 211 export default {
212 212 name: 'WtXsthdDetailView',
... ... @@ -298,12 +298,23 @@ export default {
298 298 },
299 299 formatDjrq(ts) {
300 300 if (ts == null || ts === '') return '无'
301   - const d = new Date(typeof ts === 'number' ? ts : Number(ts))
  301 + const raw = typeof ts === 'string' ? ts.trim() : ts
  302 + if (raw === '') return '无'
  303 + let d
  304 + if (typeof raw === 'number') {
  305 + d = new Date(raw)
  306 + } else {
  307 + const n = Number(raw)
  308 + d = !isNaN(n) ? new Date(n) : new Date(String(raw).replace(/-/g, '/'))
  309 + }
302 310 if (isNaN(d.getTime())) return '无'
303 311 const y = d.getFullYear()
304 312 const m = String(d.getMonth() + 1).padStart(2, '0')
305 313 const day = String(d.getDate()).padStart(2, '0')
306   - return `${y}-${m}-${day}`
  314 + const h = String(d.getHours()).padStart(2, '0')
  315 + const mi = String(d.getMinutes()).padStart(2, '0')
  316 + const s = String(d.getSeconds()).padStart(2, '0')
  317 + return `${y}-${m}-${day} ${h}:${mi}:${s}`
307 318 },
308 319 getSummaries(param) {
309 320 const { columns, data } = param
... ... @@ -419,7 +430,7 @@ export default {
419 430 previewDataInterface('681758216954053893').then(res => {
420 431 this.cjckOptions = res.data || []
421 432 })
422   - getDictionaryDataSelector('681761709836207365').then(res => {
  433 + getAccountSelector().then(res => {
423 434 this.skzhOptions = res.data.list || []
424 435 })
425 436 }
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsthd/index.vue
... ... @@ -161,13 +161,13 @@
161 161 </template>
162 162 <script>
163 163 import request from '@/utils/request'
164   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
165 164 import NCCForm from './Form'
166 165 import DetailView from './detail-view'
167 166 import XsckdDetailView from '../wtXsckd/detail-view'
168 167 import ExportBox from './ExportBox'
169 168 import { previewDataInterface } from '@/api/systemData/dataInterface'
170 169 import { promptApprovalRemark, postApproveGeneric, postRejectGeneric } from '@/utils/wtRejectApproval'
  170 + import { getAccountSelector } from '@/api/extend/wtAccount'
171 171 export default {
172 172 components: { NCCForm, DetailView, XsckdDetailView, ExportBox },
173 173 data() {
... ... @@ -280,7 +280,7 @@
280 280 });
281 281 },
282 282 getskzhOptions(){
283   - getDictionaryDataSelector('681761709836207365').then(res => {
  283 + getAccountSelector().then(res => {
284 284 this.skzhOptions = res.data.list
285 285 });
286 286 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXswtdxfhd/Form.vue
... ... @@ -280,10 +280,10 @@
280 280 </template>
281 281 <script>
282 282 import request from '@/utils/request'
283   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
284 283 import { previewDataInterface } from '@/api/systemData/dataInterface'
285 284 import BarcodeSelect from '../wtCgrkd/BarcodeSelect.vue'
286 285 import SerialNumberSelect from './SerialNumberSelect.vue'
  286 + import { getAccountSelector } from '@/api/extend/wtAccount'
287 287 export default {
288 288 components: { BarcodeSelect, SerialNumberSelect },
289 289 props: [],
... ... @@ -632,7 +632,7 @@
632 632 });
633 633 },
634 634 getskzhOptions(){
635   - getDictionaryDataSelector('681761709836207365').then(res => {
  635 + getAccountSelector().then(res => {
636 636 this.skzhOptions = res.data.list
637 637 });
638 638 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXswtdxfhd/detail-view.vue
... ... @@ -133,11 +133,6 @@
133 133 <span class="cell-nowrap mx-cell__money">{{ formatMoneyCol(scope.row.je) }}</span>
134 134 </template>
135 135 </el-table-column>
136   - <el-table-column prop="cbje" label="成本" width="96" align="right">
137   - <template slot-scope="scope">
138   - <span class="cell-nowrap">{{ formatMoneyCol(scope.row.cbje) }}</span>
139   - </template>
140   - </el-table-column>
141 136 <el-table-column label="序列号" min-width="168">
142 137 <template slot-scope="scope">
143 138 <div v-if="scope.row.selectedSerialNumbers && scope.row.selectedSerialNumbers.length" class="sn-tags">
... ... @@ -180,12 +175,6 @@
180 175 {{ displayDiscountAmount }}
181 176 </span>
182 177 </el-descriptions-item>
183   - <el-descriptions-item label="出库成本">
184   - <span class="cell-nowrap">
185   - <i class="el-icon-s-grid desc-icon desc-icon--info" />
186   - {{ formatMoneyCol(detail.cbje) }}
187   - </span>
188   - </el-descriptions-item>
189 178 <el-descriptions-item label="制单人">
190 179 <span class="cell-nowrap">
191 180 <i class="el-icon-edit-outline desc-icon desc-icon--muted" />
... ... @@ -225,9 +214,9 @@
225 214  
226 215 <script>
227 216 import request from '@/utils/request'
228   -import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
229 217 import { previewDataInterface } from '@/api/systemData/dataInterface'
230 218 import { dynamicText } from '@/filters'
  219 +import { getAccountSelector } from '@/api/extend/wtAccount'
231 220  
232 221 export default {
233 222 name: 'WtXswtdxfhdDetailView',
... ... @@ -330,12 +319,23 @@ export default {
330 319 },
331 320 formatDjrq(ts) {
332 321 if (ts == null || ts === '') return '无'
333   - const d = new Date(typeof ts === 'number' ? ts : Number(ts))
  322 + const raw = typeof ts === 'string' ? ts.trim() : ts
  323 + if (raw === '') return '无'
  324 + let d
  325 + if (typeof raw === 'number') {
  326 + d = new Date(raw)
  327 + } else {
  328 + const n = Number(raw)
  329 + d = !isNaN(n) ? new Date(n) : new Date(String(raw).replace(/-/g, '/'))
  330 + }
334 331 if (isNaN(d.getTime())) return '无'
335 332 const y = d.getFullYear()
336 333 const m = String(d.getMonth() + 1).padStart(2, '0')
337 334 const day = String(d.getDate()).padStart(2, '0')
338   - return `${y}-${m}-${day}`
  335 + const h = String(d.getHours()).padStart(2, '0')
  336 + const mi = String(d.getMinutes()).padStart(2, '0')
  337 + const s = String(d.getSeconds()).padStart(2, '0')
  338 + return `${y}-${m}-${day} ${h}:${mi}:${s}`
339 339 },
340 340 getSummaries(param) {
341 341 const { columns, data } = param
... ... @@ -351,10 +351,6 @@ export default {
351 351 sums[index] = data
352 352 .reduce((t, row) => t + (parseFloat(row.je) || 0), 0)
353 353 .toFixed(2)
354   - } else if (column.property === 'cbje') {
355   - sums[index] = data
356   - .reduce((t, row) => t + (parseFloat(row.cbje) || 0), 0)
357   - .toFixed(2)
358 354 } else {
359 355 sums[index] = ''
360 356 }
... ... @@ -396,7 +392,7 @@ export default {
396 392 previewDataInterface('681758216954053893').then(res => {
397 393 this.cjckOptions = res.data || []
398 394 })
399   - getDictionaryDataSelector('681761709836207365').then(res => {
  395 + getAccountSelector().then(res => {
400 396 this.skzhOptions = res.data.list || []
401 397 })
402 398 request({
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXswtdxfhd/index.vue
... ... @@ -165,12 +165,12 @@
165 165 </template>
166 166 <script>
167 167 import request from '@/utils/request'
168   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
169 168 import NCCForm from './Form'
170 169 import DetailView from './detail-view'
171 170 import ExportBox from './ExportBox'
172 171 import { previewDataInterface } from '@/api/systemData/dataInterface'
173 172 import { promptApprovalRemark, postApproveGeneric } from '@/utils/wtRejectApproval'
  173 + import { getAccountSelector } from '@/api/extend/wtAccount'
174 174 export default {
175 175 components: { NCCForm, DetailView, ExportBox },
176 176 data() {
... ... @@ -244,7 +244,7 @@
244 244 });
245 245 },
246 246 getskzhOptions(){
247   - getDictionaryDataSelector('681761709836207365').then(res => {
  247 + getAccountSelector().then(res => {
248 248 this.skzhOptions = res.data.list
249 249 });
250 250 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXswtdxjsd/Form.vue
... ... @@ -278,11 +278,11 @@
278 278 </template>
279 279 <script>
280 280 import request from '@/utils/request'
281   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
282 281 import { previewDataInterface } from '@/api/systemData/dataInterface'
283 282 import BarcodeSelect from '../wtCgrkd/BarcodeSelect.vue'
284 283 import SerialNumberSelect from './SerialNumberSelect.vue'
285 284 import ShipmentOrderSelect from './ShipmentOrderSelect.vue'
  285 + import { getAccountSelector } from '@/api/extend/wtAccount'
286 286 export default {
287 287 components: { BarcodeSelect, SerialNumberSelect, ShipmentOrderSelect },
288 288 props: [],
... ... @@ -596,7 +596,7 @@
596 596 });
597 597 },
598 598 getskzhOptions(){
599   - getDictionaryDataSelector('681761709836207365').then(res => {
  599 + getAccountSelector().then(res => {
600 600 this.skzhOptions = res.data.list
601 601 });
602 602 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXswtdxjsd/detail-view.vue
... ... @@ -230,9 +230,9 @@
230 230  
231 231 <script>
232 232 import request from '@/utils/request'
233   -import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
234 233 import { previewDataInterface } from '@/api/systemData/dataInterface'
235 234 import { dynamicText } from '@/filters'
  235 +import { getAccountSelector } from '@/api/extend/wtAccount'
236 236  
237 237 export default {
238 238 name: 'WtXswtdxjsdDetailView',
... ... @@ -303,12 +303,23 @@ export default {
303 303 },
304 304 formatDjrq(ts) {
305 305 if (ts == null || ts === '') return '无'
306   - const d = new Date(typeof ts === 'number' ? ts : Number(ts))
  306 + const raw = typeof ts === 'string' ? ts.trim() : ts
  307 + if (raw === '') return '无'
  308 + let d
  309 + if (typeof raw === 'number') {
  310 + d = new Date(raw)
  311 + } else {
  312 + const n = Number(raw)
  313 + d = !isNaN(n) ? new Date(n) : new Date(String(raw).replace(/-/g, '/'))
  314 + }
307 315 if (isNaN(d.getTime())) return '无'
308 316 const y = d.getFullYear()
309 317 const m = String(d.getMonth() + 1).padStart(2, '0')
310 318 const day = String(d.getDate()).padStart(2, '0')
311   - return `${y}-${m}-${day}`
  319 + const h = String(d.getHours()).padStart(2, '0')
  320 + const mi = String(d.getMinutes()).padStart(2, '0')
  321 + const s = String(d.getSeconds()).padStart(2, '0')
  322 + return `${y}-${m}-${day} ${h}:${mi}:${s}`
312 323 },
313 324 getSummaries(param) {
314 325 const { columns, data } = param
... ... @@ -365,7 +376,7 @@ export default {
365 376 previewDataInterface('681758216954053893').then(res => {
366 377 this.cjckOptions = res.data || []
367 378 })
368   - getDictionaryDataSelector('681761709836207365').then(res => {
  379 + getAccountSelector().then(res => {
369 380 this.skzhOptions = res.data.list || []
370 381 })
371 382 }
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXswtdxjsd/index.vue
... ... @@ -155,12 +155,12 @@
155 155 </template>
156 156 <script>
157 157 import request from '@/utils/request'
158   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
159 158 import NCCForm from './Form'
160 159 import DetailView from './detail-view'
161 160 import ExportBox from './ExportBox'
162 161 import { previewDataInterface } from '@/api/systemData/dataInterface'
163 162 import { promptApprovalRemark, postApproveGeneric } from '@/utils/wtRejectApproval'
  163 + import { getAccountSelector } from '@/api/extend/wtAccount'
164 164 export default {
165 165 components: { NCCForm, DetailView, ExportBox },
166 166 data() {
... ... @@ -231,7 +231,7 @@
231 231 });
232 232 },
233 233 getskzhOptions(){
234   - getDictionaryDataSelector('681761709836207365').then(res => {
  234 + getAccountSelector().then(res => {
235 235 this.skzhOptions = res.data.list
236 236 });
237 237 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXswtdxthd/Form.vue
... ... @@ -264,10 +264,10 @@
264 264 </template>
265 265 <script>
266 266 import request from '@/utils/request'
267   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
268 267 import { previewDataInterface } from '@/api/systemData/dataInterface'
269 268 import SerialNumberSelect from '../wtXsckd/SerialNumberSelect.vue'
270 269 import ShipmentOrderSelect from '../wtXswtdxjsd/ShipmentOrderSelect.vue'
  270 + import { getAccountSelector } from '@/api/extend/wtAccount'
271 271 export default {
272 272 components: { SerialNumberSelect, ShipmentOrderSelect },
273 273 props: [],
... ... @@ -363,7 +363,7 @@
363 363 });
364 364 },
365 365 getskzhOptions(){
366   - getDictionaryDataSelector('681761709836207365').then(res => {
  366 + getAccountSelector().then(res => {
367 367 this.skzhOptions = res.data.list
368 368 });
369 369 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXswtdxthd/detail-view.vue
... ... @@ -196,9 +196,9 @@
196 196  
197 197 <script>
198 198 import request from '@/utils/request'
199   -import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
200 199 import { previewDataInterface } from '@/api/systemData/dataInterface'
201 200 import { dynamicText } from '@/filters'
  201 +import { getAccountSelector } from '@/api/extend/wtAccount'
202 202  
203 203 export default {
204 204 name: 'WtXswtdxthdDetailView',
... ... @@ -287,12 +287,23 @@ export default {
287 287 },
288 288 formatDjrq(ts) {
289 289 if (ts == null || ts === '') return '无'
290   - const d = new Date(typeof ts === 'number' ? ts : Number(ts))
  290 + const raw = typeof ts === 'string' ? ts.trim() : ts
  291 + if (raw === '') return '无'
  292 + let d
  293 + if (typeof raw === 'number') {
  294 + d = new Date(raw)
  295 + } else {
  296 + const n = Number(raw)
  297 + d = !isNaN(n) ? new Date(n) : new Date(String(raw).replace(/-/g, '/'))
  298 + }
291 299 if (isNaN(d.getTime())) return '无'
292 300 const y = d.getFullYear()
293 301 const m = String(d.getMonth() + 1).padStart(2, '0')
294 302 const day = String(d.getDate()).padStart(2, '0')
295   - return `${y}-${m}-${day}`
  303 + const h = String(d.getHours()).padStart(2, '0')
  304 + const mi = String(d.getMinutes()).padStart(2, '0')
  305 + const s = String(d.getSeconds()).padStart(2, '0')
  306 + return `${y}-${m}-${day} ${h}:${mi}:${s}`
296 307 },
297 308 getSummaries(param) {
298 309 const { columns, data } = param
... ... @@ -405,7 +416,7 @@ export default {
405 416 previewDataInterface('681758216954053893').then(res => {
406 417 this.cjckOptions = res.data || []
407 418 })
408   - getDictionaryDataSelector('681761709836207365').then(res => {
  419 + getAccountSelector().then(res => {
409 420 this.skzhOptions = res.data.list || []
410 421 })
411 422 }
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXswtdxthd/index.vue
... ... @@ -156,12 +156,12 @@
156 156 </template>
157 157 <script>
158 158 import request from '@/utils/request'
159   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
160 159 import NCCForm from './Form'
161 160 import DetailView from './detail-view'
162 161 import ExportBox from './ExportBox'
163 162 import { previewDataInterface } from '@/api/systemData/dataInterface'
164 163 import { promptApprovalRemark, postApproveGeneric } from '@/utils/wtRejectApproval'
  164 + import { getAccountSelector } from '@/api/extend/wtAccount'
165 165 export default {
166 166 components: { NCCForm, DetailView, ExportBox },
167 167 data() {
... ... @@ -234,7 +234,7 @@
234 234 });
235 235 },
236 236 getskzhOptions(){
237   - getDictionaryDataSelector('681761709836207365').then(res => {
  237 + getAccountSelector().then(res => {
238 238 this.skzhOptions = res.data.list
239 239 });
240 240 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYfkzjjs/Form.vue
... ... @@ -127,6 +127,7 @@
127 127 import request from '@/utils/request'
128 128 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
129 129 import { previewDataInterface } from '@/api/systemData/dataInterface'
  130 + import { getAccountSelector } from '@/api/extend/wtAccount'
130 131 export default {
131 132 components: {},
132 133 props: [],
... ... @@ -202,17 +203,17 @@
202 203 });
203 204 },
204 205 getzhbhOptions(){
205   - getDictionaryDataSelector('681761709836207365').then(res => {
  206 + getAccountSelector().then(res => {
206 207 this.zhbhOptions = res.data.list
207 208 });
208 209 },
209 210 getfkzhOptions(){
210   - getDictionaryDataSelector('681761709836207365').then(res => {
  211 + getAccountSelector().then(res => {
211 212 this.fkzhOptions = res.data.list
212 213 });
213 214 },
214 215 getskzhOptions(){
215   - getDictionaryDataSelector('681761709836207365').then(res => {
  216 + getAccountSelector().then(res => {
216 217 this.skzhOptions = res.data.list
217 218 });
218 219 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYfkzjjs/index.vue
... ... @@ -121,10 +121,10 @@
121 121 </template>
122 122 <script>
123 123 import request from '@/utils/request'
124   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
125 124 import NCCForm from './Form'
126 125 import DetailView from './detail-view'
127 126 import ExportBox from './ExportBox'
  127 + import { getAccountSelector } from '@/api/extend/wtAccount'
128 128 export default {
129 129 components: { NCCForm, DetailView, ExportBox },
130 130 data() {
... ... @@ -178,12 +178,12 @@
178 178 },
179 179 methods: {
180 180 getfkzhOptions(){
181   - getDictionaryDataSelector('681761709836207365').then(res => {
  181 + getAccountSelector().then(res => {
182 182 this.fkzhOptions = res.data.list
183 183 });
184 184 },
185 185 getskzhOptions(){
186   - getDictionaryDataSelector('681761709836207365').then(res => {
  186 + getAccountSelector().then(res => {
187 187 this.skzhOptions = res.data.list
188 188 });
189 189 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYfkzjjs_js/Form.vue
... ... @@ -110,6 +110,7 @@
110 110 import request from '@/utils/request'
111 111 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
112 112 import { previewDataInterface } from '@/api/systemData/dataInterface'
  113 + import { getAccountSelector } from '@/api/extend/wtAccount'
113 114 export default {
114 115 components: {},
115 116 props: [],
... ... @@ -183,17 +184,17 @@
183 184 });
184 185 },
185 186 getzhbhOptions(){
186   - getDictionaryDataSelector('681761709836207365').then(res => {
  187 + getAccountSelector().then(res => {
187 188 this.zhbhOptions = res.data.list
188 189 });
189 190 },
190 191 getfkzhOptions(){
191   - getDictionaryDataSelector('681761709836207365').then(res => {
  192 + getAccountSelector().then(res => {
192 193 this.fkzhOptions = res.data.list
193 194 });
194 195 },
195 196 getskzhOptions(){
196   - getDictionaryDataSelector('681761709836207365').then(res => {
  197 + getAccountSelector().then(res => {
197 198 this.skzhOptions = res.data.list
198 199 });
199 200 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYfkzjjs_js/index.vue
... ... @@ -121,10 +121,10 @@
121 121 </template>
122 122 <script>
123 123 import request from '@/utils/request'
124   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
125 124 import NCCForm from './Form'
126 125 import DetailView from './detail-view'
127 126 import ExportBox from './ExportBox'
  127 + import { getAccountSelector } from '@/api/extend/wtAccount'
128 128 export default {
129 129 components: { NCCForm, DetailView, ExportBox },
130 130 data() {
... ... @@ -178,12 +178,12 @@
178 178 },
179 179 methods: {
180 180 getfkzhOptions(){
181   - getDictionaryDataSelector('681761709836207365').then(res => {
  181 + getAccountSelector().then(res => {
182 182 this.fkzhOptions = res.data.list
183 183 });
184 184 },
185 185 getskzhOptions(){
186   - getDictionaryDataSelector('681761709836207365').then(res => {
  186 + getAccountSelector().then(res => {
187 187 this.skzhOptions = res.data.list
188 188 });
189 189 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYsckd/Form.vue
... ... @@ -278,10 +278,10 @@
278 278 </template>
279 279 <script>
280 280 import request from '@/utils/request'
281   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
282 281 import { previewDataInterface } from '@/api/systemData/dataInterface'
283 282 import BarcodeSelect from '../wtCgrkd/BarcodeSelect.vue'
284 283 import SerialNumberSelect from './SerialNumberSelect.vue'
  284 + import { getAccountSelector } from '@/api/extend/wtAccount'
285 285 export default {
286 286 components: { BarcodeSelect, SerialNumberSelect },
287 287 props: [],
... ... @@ -608,7 +608,7 @@
608 608 });
609 609 },
610 610 getskzhOptions(){
611   - getDictionaryDataSelector('681761709836207365').then(res => {
  611 + getAccountSelector().then(res => {
612 612 this.skzhOptions = res.data.list
613 613 });
614 614 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYsckd/detail-view.vue
... ... @@ -139,11 +139,6 @@
139 139 <span class="cell-nowrap mx-cell__money">{{ formatMoneyCol(scope.row.je) }}</span>
140 140 </template>
141 141 </el-table-column>
142   - <el-table-column prop="cbje" label="成本" width="96" align="right">
143   - <template slot-scope="scope">
144   - <span class="cell-nowrap">{{ formatMoneyCol(scope.row.cbje) }}</span>
145   - </template>
146   - </el-table-column>
147 142 <el-table-column label="序列号" min-width="168">
148 143 <template slot-scope="scope">
149 144 <div v-if="scope.row.selectedSerialNumbers && scope.row.selectedSerialNumbers.length" class="sn-tags">
... ... @@ -186,12 +181,6 @@
186 181 {{ displayDiscountAmount }}
187 182 </span>
188 183 </el-descriptions-item>
189   - <el-descriptions-item label="出库成本">
190   - <span class="cell-nowrap">
191   - <i class="el-icon-s-grid desc-icon desc-icon--info" />
192   - {{ formatMoneyCol(detail.cbje) }}
193   - </span>
194   - </el-descriptions-item>
195 184 <el-descriptions-item label="制单人">
196 185 <span class="cell-nowrap">
197 186 <i class="el-icon-edit-outline desc-icon desc-icon--muted" />
... ... @@ -312,9 +301,9 @@
312 301  
313 302 <script>
314 303 import request from '@/utils/request'
315   -import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
316 304 import { previewDataInterface } from '@/api/systemData/dataInterface'
317 305 import { dynamicText } from '@/filters'
  306 +import { getAccountSelector } from '@/api/extend/wtAccount'
318 307 import {
319 308 formatWtSkzhDisplay,
320 309 resolveSkzhDictionaryLabel,
... ... @@ -467,12 +456,23 @@ export default {
467 456 },
468 457 formatDjrq(ts) {
469 458 if (ts == null || ts === '') return '无'
470   - const d = new Date(typeof ts === 'number' ? ts : Number(ts))
  459 + const raw = typeof ts === 'string' ? ts.trim() : ts
  460 + if (raw === '') return '无'
  461 + let d
  462 + if (typeof raw === 'number') {
  463 + d = new Date(raw)
  464 + } else {
  465 + const n = Number(raw)
  466 + d = !isNaN(n) ? new Date(n) : new Date(String(raw).replace(/-/g, '/'))
  467 + }
471 468 if (isNaN(d.getTime())) return '无'
472 469 const y = d.getFullYear()
473 470 const m = String(d.getMonth() + 1).padStart(2, '0')
474 471 const day = String(d.getDate()).padStart(2, '0')
475   - return `${y}-${m}-${day}`
  472 + const h = String(d.getHours()).padStart(2, '0')
  473 + const mi = String(d.getMinutes()).padStart(2, '0')
  474 + const s = String(d.getSeconds()).padStart(2, '0')
  475 + return `${y}-${m}-${day} ${h}:${mi}:${s}`
476 476 },
477 477 getSummaries(param) {
478 478 const { columns, data } = param
... ... @@ -488,10 +488,6 @@ export default {
488 488 sums[index] = data
489 489 .reduce((t, row) => t + (parseFloat(row.je) || 0), 0)
490 490 .toFixed(2)
491   - } else if (column.property === 'cbje') {
492   - sums[index] = data
493   - .reduce((t, row) => t + (parseFloat(row.cbje) || 0), 0)
494   - .toFixed(2)
495 491 } else {
496 492 sums[index] = ''
497 493 }
... ... @@ -530,7 +526,7 @@ export default {
530 526 previewDataInterface('681758216954053893').then(res => {
531 527 this.cjckOptions = res.data || []
532 528 })
533   - getDictionaryDataSelector('681761709836207365').then(res => {
  529 + getAccountSelector().then(res => {
534 530 const d = res.data
535 531 this.skzhOptions =
536 532 d && Array.isArray(d.list) ? d.list : Array.isArray(d) ? d : []
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYsckd/index.vue
... ... @@ -135,9 +135,6 @@
135 135 <el-table-column label="优惠金额" align="left" min-width="90">
136 136 <template slot-scope="scope">{{ getDisplayDiscountAmount(scope.row) }}</template>
137 137 </el-table-column>
138   - <el-table-column label="出库成本" align="left" min-width="90">
139   - <template slot-scope="scope">{{ getDisplayOutboundCost(scope.row) }}</template>
140   - </el-table-column>
141 138 <el-table-column label="收款账户" prop="skzh" align="left">
142 139 <template slot-scope="scope">{{ formatSkzhRow(scope.row) }}</template>
143 140 </el-table-column>
... ... @@ -257,7 +254,6 @@
257 254 </template>
258 255 <script>
259 256 import request from '@/utils/request'
260   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
261 257 import NCCForm from './Form'
262 258 import DetailView from './detail-view'
263 259 import ExportBox from './ExportBox'
... ... @@ -265,6 +261,7 @@
265 261 import { previewDataInterface } from '@/api/systemData/dataInterface'
266 262 import { promptApprovalRemark, postApproveSalesOutbound } from '@/utils/wtRejectApproval'
267 263 import { formatWtSkzhDisplay } from '@/utils/wtComboSkzhDisplay'
  264 + import { getAccountSelector } from '@/api/extend/wtAccount'
268 265 export default {
269 266 components: { NCCForm, DetailView, ExportBox, SerialNumberSelect },
270 267 data() {
... ... @@ -307,7 +304,6 @@
307 304 { prop: 'skzh', label: '收款账户' },
308 305 { prop: 'skje', label: '收款金额' },
309 306 { prop: 'ysje', label: '优惠金额' },
310   - { prop: 'cbje', label: '出库成本' },
311 307 { prop: 'zdr', label: '制单人' },
312 308 { prop: 'shr', label: '审核人' },
313 309 { prop: 'gzr', label: '过账人' },
... ... @@ -369,10 +365,6 @@
369 365 formatSkzhRow(row) {
370 366 return formatWtSkzhDisplay(row, this.skzhOptions)
371 367 },
372   - getDisplayOutboundCost(row) {
373   - const val = parseFloat(row.cbje)
374   - return isNaN(val) ? '0.00' : val.toFixed(2)
375   - },
376 368 openDetail(id) {
377 369 if (!id) return
378 370 this.detailVisible = true
... ... @@ -454,7 +446,7 @@
454 446 });
455 447 },
456 448 getskzhOptions(){
457   - getDictionaryDataSelector('681761709836207365').then(res => {
  449 + getAccountSelector().then(res => {
458 450 this.skzhOptions = res.data.list
459 451 });
460 452 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs/Form.vue
... ... @@ -127,6 +127,7 @@
127 127 import request from '@/utils/request'
128 128 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
129 129 import { previewDataInterface } from '@/api/systemData/dataInterface'
  130 + import { getAccountSelector } from '@/api/extend/wtAccount'
130 131 export default {
131 132 components: {},
132 133 props: [],
... ... @@ -202,17 +203,17 @@
202 203 });
203 204 },
204 205 getzhbhOptions(){
205   - getDictionaryDataSelector('681761709836207365').then(res => {
  206 + getAccountSelector().then(res => {
206 207 this.zhbhOptions = res.data.list
207 208 });
208 209 },
209 210 getfkzhOptions(){
210   - getDictionaryDataSelector('681761709836207365').then(res => {
  211 + getAccountSelector().then(res => {
211 212 this.fkzhOptions = res.data.list
212 213 });
213 214 },
214 215 getskzhOptions(){
215   - getDictionaryDataSelector('681761709836207365').then(res => {
  216 + getAccountSelector().then(res => {
216 217 this.skzhOptions = res.data.list
217 218 });
218 219 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs/index.vue
... ... @@ -122,10 +122,10 @@
122 122 </template>
123 123 <script>
124 124 import request from '@/utils/request'
125   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
126 125 import NCCForm from './Form'
127 126 import DetailView from './detail-view'
128 127 import ExportBox from './ExportBox'
  128 + import { getAccountSelector } from '@/api/extend/wtAccount'
129 129 export default {
130 130 components: { NCCForm, DetailView, ExportBox },
131 131 data() {
... ... @@ -178,12 +178,12 @@
178 178 },
179 179 methods: {
180 180 getfkzhOptions(){
181   - getDictionaryDataSelector('681761709836207365').then(res => {
  181 + getAccountSelector().then(res => {
182 182 this.fkzhOptions = res.data.list
183 183 });
184 184 },
185 185 getskzhOptions(){
186   - getDictionaryDataSelector('681761709836207365').then(res => {
  186 + getAccountSelector().then(res => {
187 187 this.skzhOptions = res.data.list
188 188 });
189 189 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_hy/Form.vue
... ... @@ -152,6 +152,7 @@
152 152 import request from '@/utils/request'
153 153 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
154 154 import { previewDataInterface } from '@/api/systemData/dataInterface'
  155 + import { getAccountSelector } from '@/api/extend/wtAccount'
155 156 export default {
156 157 components: {},
157 158 props: [],
... ... @@ -234,17 +235,17 @@
234 235 });
235 236 },
236 237 getzhbhOptions(){
237   - getDictionaryDataSelector('681761709836207365').then(res => {
  238 + getAccountSelector().then(res => {
238 239 this.zhbhOptions = res.data.list
239 240 });
240 241 },
241 242 getfkzhOptions(){
242   - getDictionaryDataSelector('681761709836207365').then(res => {
  243 + getAccountSelector().then(res => {
243 244 this.fkzhOptions = res.data.list
244 245 });
245 246 },
246 247 getskzhOptions(){
247   - getDictionaryDataSelector('681761709836207365').then(res => {
  248 + getAccountSelector().then(res => {
248 249 this.skzhOptions = res.data.list
249 250 });
250 251 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_hy/detail-view.vue
... ... @@ -43,7 +43,7 @@
43 43  
44 44 <script>
45 45 import request from '@/utils/request'
46   -import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
  46 +import { getAccountSelector } from '@/api/extend/wtAccount'
47 47  
48 48 export default {
49 49 name: 'WtYskzjjsHyDetailView',
... ... @@ -60,7 +60,7 @@ export default {
60 60 },
61 61 methods: {
62 62 loadAccountOptions() {
63   - getDictionaryDataSelector('681761709836207365').then(res => {
  63 + getAccountSelector().then(res => {
64 64 this.accountOptions = (res.data && res.data.list) || []
65 65 })
66 66 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_hy/index.vue
... ... @@ -101,11 +101,11 @@
101 101 </template>
102 102 <script>
103 103 import request from '@/utils/request'
104   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
105 104 import NCCForm from './Form'
106 105 import DetailView from './detail-view'
107 106 import ExportBox from './ExportBox'
108 107 import { previewDataInterface } from '@/api/systemData/dataInterface'
  108 + import { getAccountSelector } from '@/api/extend/wtAccount'
109 109 export default {
110 110 components: { NCCForm, ExportBox, DetailView },
111 111 data() {
... ... @@ -155,12 +155,12 @@
155 155 },
156 156 methods: {
157 157 getfkzhOptions(){
158   - getDictionaryDataSelector('681761709836207365').then(res => {
  158 + getAccountSelector().then(res => {
159 159 this.fkzhOptions = res.data.list
160 160 });
161 161 },
162 162 getskzhOptions(){
163   - getDictionaryDataSelector('681761709836207365').then(res => {
  163 + getAccountSelector().then(res => {
164 164 this.skzhOptions = res.data.list
165 165 });
166 166 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_js/Form.vue
... ... @@ -110,6 +110,7 @@
110 110 import request from '@/utils/request'
111 111 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
112 112 import { previewDataInterface } from '@/api/systemData/dataInterface'
  113 + import { getAccountSelector } from '@/api/extend/wtAccount'
113 114 export default {
114 115 components: {},
115 116 props: [],
... ... @@ -183,17 +184,17 @@
183 184 });
184 185 },
185 186 getzhbhOptions(){
186   - getDictionaryDataSelector('681761709836207365').then(res => {
  187 + getAccountSelector().then(res => {
187 188 this.zhbhOptions = res.data.list
188 189 });
189 190 },
190 191 getfkzhOptions(){
191   - getDictionaryDataSelector('681761709836207365').then(res => {
  192 + getAccountSelector().then(res => {
192 193 this.fkzhOptions = res.data.list
193 194 });
194 195 },
195 196 getskzhOptions(){
196   - getDictionaryDataSelector('681761709836207365').then(res => {
  197 + getAccountSelector().then(res => {
197 198 this.skzhOptions = res.data.list
198 199 });
199 200 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_js/index.vue
... ... @@ -121,10 +121,10 @@
121 121 </template>
122 122 <script>
123 123 import request from '@/utils/request'
124   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
125 124 import NCCForm from './Form'
126 125 import DetailView from './detail-view'
127 126 import ExportBox from './ExportBox'
  127 + import { getAccountSelector } from '@/api/extend/wtAccount'
128 128 export default {
129 129 components: { NCCForm, DetailView, ExportBox },
130 130 data() {
... ... @@ -178,12 +178,12 @@
178 178 },
179 179 methods: {
180 180 getfkzhOptions(){
181   - getDictionaryDataSelector('681761709836207365').then(res => {
  181 + getAccountSelector().then(res => {
182 182 this.fkzhOptions = res.data.list
183 183 });
184 184 },
185 185 getskzhOptions(){
186   - getDictionaryDataSelector('681761709836207365').then(res => {
  186 + getAccountSelector().then(res => {
187 187 this.skzhOptions = res.data.list
188 188 });
189 189 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_qt/Form.vue
... ... @@ -120,6 +120,7 @@
120 120 <script>
121 121 import request from '@/utils/request'
122 122 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
  123 + import { getAccountSelector } from '@/api/extend/wtAccount'
123 124 export default {
124 125 components: {},
125 126 props: [],
... ... @@ -177,12 +178,12 @@
177 178 });
178 179 },
179 180 getfkzhOptions(){
180   - getDictionaryDataSelector('681761709836207365').then(res => {
  181 + getAccountSelector().then(res => {
181 182 this.fkzhOptions = res.data.list
182 183 });
183 184 },
184 185 getskzhOptions(){
185   - getDictionaryDataSelector('681761709836207365').then(res => {
  186 + getAccountSelector().then(res => {
186 187 this.skzhOptions = res.data.list
187 188 });
188 189 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_xj/Form.vue
... ... @@ -121,6 +121,7 @@
121 121 import request from '@/utils/request'
122 122 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
123 123 import { previewDataInterface } from '@/api/systemData/dataInterface'
  124 + import { getAccountSelector } from '@/api/extend/wtAccount'
124 125 export default {
125 126 components: {},
126 127 props: [],
... ... @@ -198,17 +199,17 @@
198 199 });
199 200 },
200 201 getzhbhOptions(){
201   - getDictionaryDataSelector('681761709836207365').then(res => {
  202 + getAccountSelector().then(res => {
202 203 this.zhbhOptions = res.data.list
203 204 });
204 205 },
205 206 getfkzhOptions(){
206   - getDictionaryDataSelector('681761709836207365').then(res => {
  207 + getAccountSelector().then(res => {
207 208 this.fkzhOptions = res.data.list
208 209 });
209 210 },
210 211 getskzhOptions(){
211   - getDictionaryDataSelector('681761709836207365').then(res => {
  212 + getAccountSelector().then(res => {
212 213 this.skzhOptions = res.data.list
213 214 });
214 215 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_xj/detail-view.vue
... ... @@ -44,6 +44,7 @@
44 44 <script>
45 45 import request from '@/utils/request'
46 46 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
  47 +import { getAccountSelector } from '@/api/extend/wtAccount'
47 48  
48 49 export default {
49 50 name: 'WtYskzjjsXjDetailView',
... ... @@ -81,7 +82,7 @@ export default {
81 82 })
82 83 },
83 84 loadAccounts() {
84   - getDictionaryDataSelector('681761709836207365').then(res => {
  85 + getAccountSelector().then(res => {
85 86 this.accountOptions = res.data.list || []
86 87 })
87 88 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_xj/index.vue
... ... @@ -118,10 +118,10 @@
118 118 </template>
119 119 <script>
120 120 import request from '@/utils/request'
121   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
122 121 import NCCForm from './Form'
123 122 import DetailView from './detail-view'
124 123 import ExportBox from './ExportBox'
  124 + import { getAccountSelector } from '@/api/extend/wtAccount'
125 125 export default {
126 126 components: { NCCForm, DetailView, ExportBox },
127 127 data() {
... ... @@ -170,12 +170,12 @@
170 170 },
171 171 methods: {
172 172 getfkzhOptions(){
173   - getDictionaryDataSelector('681761709836207365').then(res => {
  173 + getAccountSelector().then(res => {
174 174 this.fkzhOptions = res.data.list
175 175 });
176 176 },
177 177 getskzhOptions(){
178   - getDictionaryDataSelector('681761709836207365').then(res => {
  178 + getAccountSelector().then(res => {
179 179 this.skzhOptions = res.data.list
180 180 });
181 181 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_zk/Form.vue
... ... @@ -106,6 +106,7 @@
106 106 import request from '@/utils/request'
107 107 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
108 108 import { previewDataInterface } from '@/api/systemData/dataInterface'
  109 + import { getAccountSelector } from '@/api/extend/wtAccount'
109 110 export default {
110 111 components: {},
111 112 props: [],
... ... @@ -183,17 +184,17 @@
183 184 });
184 185 },
185 186 getzhbhOptions(){
186   - getDictionaryDataSelector('681761709836207365').then(res => {
  187 + getAccountSelector().then(res => {
187 188 this.zhbhOptions = res.data.list
188 189 });
189 190 },
190 191 getfkzhOptions(){
191   - getDictionaryDataSelector('681761709836207365').then(res => {
  192 + getAccountSelector().then(res => {
192 193 this.fkzhOptions = res.data.list
193 194 });
194 195 },
195 196 getskzhOptions(){
196   - getDictionaryDataSelector('681761709836207365').then(res => {
  197 + getAccountSelector().then(res => {
197 198 this.skzhOptions = res.data.list
198 199 });
199 200 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_zk/detail-view.vue
... ... @@ -47,7 +47,7 @@
47 47  
48 48 <script>
49 49 import request from '@/utils/request'
50   -import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
  50 +import { getAccountSelector } from '@/api/extend/wtAccount'
51 51  
52 52 export default {
53 53 name: 'WtYskzjjsZkDetailView',
... ... @@ -64,7 +64,7 @@ export default {
64 64 },
65 65 methods: {
66 66 getZhOptions() {
67   - getDictionaryDataSelector('681761709836207365').then(res => {
  67 + getAccountSelector().then(res => {
68 68 this.zhOptions = (res.data && res.data.list) || []
69 69 })
70 70 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_zk/index.vue
... ... @@ -126,10 +126,10 @@
126 126 </template>
127 127 <script>
128 128 import request from '@/utils/request'
129   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
130 129 import NCCForm from './Form'
131 130 import DetailView from './detail-view'
132 131 import ExportBox from './ExportBox'
  132 + import { getAccountSelector } from '@/api/extend/wtAccount'
133 133 export default {
134 134 components: { NCCForm, DetailView, ExportBox },
135 135 data() {
... ... @@ -180,12 +180,12 @@
180 180 },
181 181 methods: {
182 182 getfkzhOptions(){
183   - getDictionaryDataSelector('681761709836207365').then(res => {
  183 + getAccountSelector().then(res => {
184 184 this.fkzhOptions = res.data.list
185 185 });
186 186 },
187 187 getskzhOptions(){
188   - getDictionaryDataSelector('681761709836207365').then(res => {
  188 + getAccountSelector().then(res => {
189 189 this.skzhOptions = res.data.list
190 190 });
191 191 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYsthd copy/Form.vue
... ... @@ -223,9 +223,9 @@
223 223 </template>
224 224 <script>
225 225 import request from '@/utils/request'
226   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
227 226 import { previewDataInterface } from '@/api/systemData/dataInterface'
228 227 import SerialNumberSelect from '../wtXsckd/SerialNumberSelect.vue'
  228 + import { getAccountSelector } from '@/api/extend/wtAccount'
229 229 export default {
230 230 components: { SerialNumberSelect },
231 231 props: [],
... ... @@ -317,7 +317,7 @@
317 317 });
318 318 },
319 319 getskzhOptions(){
320   - getDictionaryDataSelector('681761709836207365').then(res => {
  320 + getAccountSelector().then(res => {
321 321 this.skzhOptions = res.data.list
322 322 });
323 323 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYsthd copy/index.vue
... ... @@ -127,10 +127,10 @@
127 127 </template>
128 128 <script>
129 129 import request from '@/utils/request'
130   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
131 130 import NCCForm from './Form'
132 131 import ExportBox from './ExportBox'
133 132 import { previewDataInterface } from '@/api/systemData/dataInterface'
  133 + import { getAccountSelector } from '@/api/extend/wtAccount'
134 134 export default {
135 135 components: { NCCForm, ExportBox },
136 136 data() {
... ... @@ -199,7 +199,7 @@
199 199 });
200 200 },
201 201 getskzhOptions(){
202   - getDictionaryDataSelector('681761709836207365').then(res => {
  202 + getAccountSelector().then(res => {
203 203 this.skzhOptions = res.data.list
204 204 });
205 205 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYsthd/Form.vue
... ... @@ -251,10 +251,10 @@
251 251 </template>
252 252 <script>
253 253 import request from '@/utils/request'
254   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
255 254 import { previewDataInterface } from '@/api/systemData/dataInterface'
256 255 import SerialNumberSelect from '../wtXsckd/SerialNumberSelect.vue'
257 256 import ShipmentOrderSelect from '../wtXswtdxjsd/ShipmentOrderSelect.vue'
  257 + import { getAccountSelector } from '@/api/extend/wtAccount'
258 258 export default {
259 259 components: { SerialNumberSelect, ShipmentOrderSelect },
260 260 props: [],
... ... @@ -347,7 +347,7 @@
347 347 });
348 348 },
349 349 getskzhOptions(){
350   - getDictionaryDataSelector('681761709836207365').then(res => {
  350 + getAccountSelector().then(res => {
351 351 this.skzhOptions = res.data.list
352 352 });
353 353 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYsthd/detail-view.vue
... ... @@ -201,10 +201,10 @@
201 201 <script>
202 202 import request from '@/utils/request'
203 203 import { getUserInfoList } from '@/api/permission/user'
204   -import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
205 204 import { previewDataInterface } from '@/api/systemData/dataInterface'
206 205 import { dynamicText } from '@/filters'
207 206 import YsckdDetailView from '../wtYsckd/detail-view'
  207 +import { getAccountSelector } from '@/api/extend/wtAccount'
208 208  
209 209 export default {
210 210 name: 'WtYsthdDetailView',
... ... @@ -289,12 +289,23 @@ export default {
289 289 },
290 290 formatDjrq(ts) {
291 291 if (ts == null || ts === '') return '无'
292   - const d = new Date(typeof ts === 'number' ? ts : Number(ts))
  292 + const raw = typeof ts === 'string' ? ts.trim() : ts
  293 + if (raw === '') return '无'
  294 + let d
  295 + if (typeof raw === 'number') {
  296 + d = new Date(raw)
  297 + } else {
  298 + const n = Number(raw)
  299 + d = !isNaN(n) ? new Date(n) : new Date(String(raw).replace(/-/g, '/'))
  300 + }
293 301 if (isNaN(d.getTime())) return '无'
294 302 const y = d.getFullYear()
295 303 const m = String(d.getMonth() + 1).padStart(2, '0')
296 304 const day = String(d.getDate()).padStart(2, '0')
297   - return `${y}-${m}-${day}`
  305 + const h = String(d.getHours()).padStart(2, '0')
  306 + const mi = String(d.getMinutes()).padStart(2, '0')
  307 + const s = String(d.getSeconds()).padStart(2, '0')
  308 + return `${y}-${m}-${day} ${h}:${mi}:${s}`
298 309 },
299 310 getSummaries(param) {
300 311 const { columns, data } = param
... ... @@ -418,7 +429,7 @@ export default {
418 429 previewDataInterface('681758216954053893').then(res => {
419 430 this.cjckOptions = res.data || []
420 431 })
421   - getDictionaryDataSelector('681761709836207365').then(res => {
  432 + getAccountSelector().then(res => {
422 433 this.skzhOptions = res.data.list || []
423 434 })
424 435 }
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYsthd/index.vue
... ... @@ -159,13 +159,13 @@
159 159 </template>
160 160 <script>
161 161 import request from '@/utils/request'
162   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
163 162 import NCCForm from './Form'
164 163 import DetailView from './detail-view'
165 164 import YsckdDetailView from '../wtYsckd/detail-view'
166 165 import ExportBox from './ExportBox'
167 166 import { previewDataInterface } from '@/api/systemData/dataInterface'
168 167 import { promptApprovalRemark, postApproveGeneric } from '@/utils/wtRejectApproval'
  168 + import { getAccountSelector } from '@/api/extend/wtAccount'
169 169 export default {
170 170 components: { NCCForm, DetailView, YsckdDetailView, ExportBox },
171 171 data() {
... ... @@ -279,7 +279,7 @@
279 279 });
280 280 },
281 281 getskzhOptions(){
282   - getDictionaryDataSelector('681761709836207365').then(res => {
  282 + getAccountSelector().then(res => {
283 283 this.skzhOptions = res.data.list
284 284 });
285 285 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtZkd/Form.vue
... ... @@ -92,8 +92,8 @@
92 92 </template>
93 93 <script>
94 94 import request from '@/utils/request'
95   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
96 95 import { previewDataInterface } from '@/api/systemData/dataInterface'
  96 + import { getAccountSelector } from '@/api/extend/wtAccount'
97 97 export default {
98 98 components: {},
99 99 props: [],
... ... @@ -134,12 +134,12 @@
134 134 },
135 135 methods: {
136 136 getfkzhOptions(){
137   - getDictionaryDataSelector('681761709836207365').then(res => {
  137 + getAccountSelector().then(res => {
138 138 this.fkzhOptions = res.data.list
139 139 });
140 140 },
141 141 getskzhOptions(){
142   - getDictionaryDataSelector('681761709836207365').then(res => {
  142 + getAccountSelector().then(res => {
143 143 this.skzhOptions = res.data.list
144 144 });
145 145 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtZkd/index.vue
... ... @@ -133,10 +133,10 @@
133 133 </template>
134 134 <script>
135 135 import request from '@/utils/request'
136   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
137 136 import NCCForm from './Form'
138 137 import ExportBox from './ExportBox'
139 138 import { previewDataInterface } from '@/api/systemData/dataInterface'
  139 + import { getAccountSelector } from '@/api/extend/wtAccount'
140 140 export default {
141 141 components: { NCCForm, ExportBox },
142 142 data() {
... ... @@ -195,12 +195,12 @@
195 195 },
196 196 methods: {
197 197 getfkzhOptions(){
198   - getDictionaryDataSelector('681761709836207365').then(res => {
  198 + getAccountSelector().then(res => {
199 199 this.fkzhOptions = res.data.list
200 200 });
201 201 },
202 202 getskzhOptions(){
203   - getDictionaryDataSelector('681761709836207365').then(res => {
  203 + getAccountSelector().then(res => {
204 204 this.skzhOptions = res.data.list
205 205 });
206 206 },
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtAccount/WtAccountCrInput.cs 0 → 100644
  1 +namespace NCC.Extend.Entitys.Dto.WtAccount
  2 +{
  3 + /// <summary>
  4 + /// 账户管理 - 新建入参
  5 + /// </summary>
  6 + public class WtAccountCrInput
  7 + {
  8 + /// <summary>
  9 + /// 账户名称(必填)
  10 + /// </summary>
  11 + public string accountName { get; set; }
  12 +
  13 + /// <summary>
  14 + /// 账户分类
  15 + /// </summary>
  16 + public string category { get; set; }
  17 +
  18 + /// <summary>
  19 + /// 业务编码;留空则按 codeRule 自动生成
  20 + /// </summary>
  21 + public string accountCode { get; set; }
  22 +
  23 + /// <summary>
  24 + /// 编码生成规则:1=数字序号(SKZH00001 递增),2=名称拼音首字母缩写;默认1
  25 + /// </summary>
  26 + public int? codeRule { get; set; }
  27 +
  28 + /// <summary>
  29 + /// 排序码
  30 + /// </summary>
  31 + public int? sortCode { get; set; }
  32 + }
  33 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtAccount/WtAccountInfoOutput.cs 0 → 100644
  1 +using System;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.WtAccount
  4 +{
  5 + /// <summary>
  6 + /// 账户管理 - 详情输出
  7 + /// </summary>
  8 + public class WtAccountInfoOutput
  9 + {
  10 + /// <summary>
  11 + /// 主键
  12 + /// </summary>
  13 + public string id { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 业务编码
  17 + /// </summary>
  18 + public string accountCode { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 账户名称
  22 + /// </summary>
  23 + public string accountName { get; set; }
  24 +
  25 + /// <summary>
  26 + /// 账户分类
  27 + /// </summary>
  28 + public string category { get; set; }
  29 +
  30 + /// <summary>
  31 + /// 状态:1=启用 0=禁用
  32 + /// </summary>
  33 + public int status { get; set; }
  34 +
  35 + /// <summary>
  36 + /// 排序码
  37 + /// </summary>
  38 + public int sortCode { get; set; }
  39 +
  40 + /// <summary>
  41 + /// 创建时间
  42 + /// </summary>
  43 + public DateTime? createTime { get; set; }
  44 + }
  45 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtAccount/WtAccountListOutput.cs 0 → 100644
  1 +namespace NCC.Extend.Entitys.Dto.WtAccount
  2 +{
  3 + /// <summary>
  4 + /// 账户管理 - 列表输出
  5 + /// </summary>
  6 + public class WtAccountListOutput
  7 + {
  8 + /// <summary>
  9 + /// 主键
  10 + /// </summary>
  11 + public string id { get; set; }
  12 +
  13 + /// <summary>
  14 + /// 业务编码
  15 + /// </summary>
  16 + public string accountCode { get; set; }
  17 +
  18 + /// <summary>
  19 + /// 账户名称
  20 + /// </summary>
  21 + public string accountName { get; set; }
  22 +
  23 + /// <summary>
  24 + /// 账户分类
  25 + /// </summary>
  26 + public string category { get; set; }
  27 +
  28 + /// <summary>
  29 + /// 状态:1=启用 0=禁用
  30 + /// </summary>
  31 + public int status { get; set; }
  32 +
  33 + /// <summary>
  34 + /// 排序码
  35 + /// </summary>
  36 + public int sortCode { get; set; }
  37 + }
  38 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtAccount/WtAccountListQueryInput.cs 0 → 100644
  1 +using NCC.Common.Filter;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.WtAccount
  4 +{
  5 + /// <summary>
  6 + /// 账户管理 - 列表查询入参
  7 + /// </summary>
  8 + public class WtAccountListQueryInput : PageInputBase
  9 + {
  10 + /// <summary>
  11 + /// 选择导出数据key
  12 + /// </summary>
  13 + public string selectKey { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 导出类型
  17 + /// </summary>
  18 + public int dataType { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 账户分类(精确)
  22 + /// </summary>
  23 + public string category { get; set; }
  24 +
  25 + /// <summary>
  26 + /// 状态:1=启用 0=禁用(不传则全部)
  27 + /// </summary>
  28 + public int? status { get; set; }
  29 + }
  30 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtAccount/WtAccountUpInput.cs 0 → 100644
  1 +namespace NCC.Extend.Entitys.Dto.WtAccount
  2 +{
  3 + /// <summary>
  4 + /// 账户管理 - 更新入参
  5 + /// </summary>
  6 + public class WtAccountUpInput : WtAccountCrInput
  7 + {
  8 + /// <summary>
  9 + /// 主键
  10 + /// </summary>
  11 + public string id { get; set; }
  12 +
  13 + /// <summary>
  14 + /// 状态:1=启用 0=禁用
  15 + /// </summary>
  16 + public int? status { get; set; }
  17 + }
  18 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtPurchaseSummaryQueryInput.cs
... ... @@ -41,6 +41,21 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd
41 41 public string BillType { get; set; }
42 42  
43 43 /// <summary>
  44 + /// 下钻:商品分类主键(wt_pl.F_Id),与明细接口联用
  45 + /// </summary>
  46 + public string CategoryId { get; set; }
  47 +
  48 + /// <summary>
  49 + /// 下钻:品牌主键(wt_pp.F_Id)
  50 + /// </summary>
  51 + public string BrandId { get; set; }
  52 +
  53 + /// <summary>
  54 + /// 下钻:商品主键(wt_sp.F_Id,与明细 mx.spbh 一致)
  55 + /// </summary>
  56 + public string ProductSpId { get; set; }
  57 +
  58 + /// <summary>
44 59 /// 当前页(默认 1)
45 60 /// </summary>
46 61 public int? CurrentPage { get; set; }
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/WtAccountEntity.cs 0 → 100644
  1 +using NCC.Common.Const;
  2 +using SqlSugar;
  3 +using System;
  4 +
  5 +namespace NCC.Extend.Entitys
  6 +{
  7 + /// <summary>
  8 + /// 账户管理(独立业务表,替代原数据字典 681761709836207365)
  9 + /// </summary>
  10 + /// <remarks>
  11 + /// 建表 SQL:
  12 + /// CREATE TABLE wt_account (
  13 + /// F_Id VARCHAR(50) NOT NULL PRIMARY KEY COMMENT '主键',
  14 + /// account_code VARCHAR(32) NOT NULL COMMENT '业务编码(唯一,用于检索)',
  15 + /// account_name VARCHAR(100) NOT NULL COMMENT '账户名称',
  16 + /// category VARCHAR(64) NULL COMMENT '账户分类',
  17 + /// status INT NOT NULL DEFAULT 1 COMMENT '状态:1=启用 0=禁用',
  18 + /// sort_code INT NOT NULL DEFAULT 0 COMMENT '排序',
  19 + /// create_time DATETIME NULL COMMENT '创建时间',
  20 + /// UNIQUE INDEX IX_wt_account_code (account_code)
  21 + /// ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='账户主数据';
  22 + ///
  23 + /// 门店-账户关联继续用 wt_skzhb 表,zhmc 字段改存 wt_account.F_Id:
  24 + /// UPDATE wt_skzhb SET zhmc = (新账户ID) WHERE zhmc = (旧字典ID);
  25 + /// </remarks>
  26 + [SugarTable("wt_account")]
  27 + [Tenant(ClaimConst.TENANT_ID)]
  28 + public class WtAccountEntity
  29 + {
  30 + /// <summary>
  31 + /// 主键
  32 + /// </summary>
  33 + [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)]
  34 + public string Id { get; set; }
  35 +
  36 + /// <summary>
  37 + /// 业务编码(唯一,用于检索:数字序号 SKZH00001 或名称拼音首字母缩写)
  38 + /// </summary>
  39 + [SugarColumn(ColumnName = "account_code")]
  40 + public string AccountCode { get; set; }
  41 +
  42 + /// <summary>
  43 + /// 账户名称
  44 + /// </summary>
  45 + [SugarColumn(ColumnName = "account_name")]
  46 + public string AccountName { get; set; }
  47 +
  48 + /// <summary>
  49 + /// 账户分类
  50 + /// </summary>
  51 + [SugarColumn(ColumnName = "category")]
  52 + public string Category { get; set; }
  53 +
  54 + /// <summary>
  55 + /// 状态:1=启用 0=禁用
  56 + /// </summary>
  57 + [SugarColumn(ColumnName = "status")]
  58 + public int Status { get; set; } = 1;
  59 +
  60 + /// <summary>
  61 + /// 排序码
  62 + /// </summary>
  63 + [SugarColumn(ColumnName = "sort_code")]
  64 + public int SortCode { get; set; } = 0;
  65 +
  66 + /// <summary>
  67 + /// 创建时间
  68 + /// </summary>
  69 + [SugarColumn(ColumnName = "create_time")]
  70 + public DateTime? CreateTime { get; set; }
  71 + }
  72 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Interfaces/IWtAccountService.cs 0 → 100644
  1 +namespace NCC.Extend.Interfaces.WtAccount
  2 +{
  3 + /// <summary>
  4 + /// 账户管理服务接口
  5 + /// </summary>
  6 + public interface IWtAccountService
  7 + {
  8 + }
  9 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtAccountService.cs 0 → 100644
  1 +using NCC.Common.Core.Manager;
  2 +using NCC.Common.Enum;
  3 +using NCC.Common.Extension;
  4 +using NCC.Common.Filter;
  5 +using NCC.Common.Util;
  6 +using NCC.Dependency;
  7 +using NCC.DynamicApiController;
  8 +using NCC.FriendlyException;
  9 +using NCC.Extend.Interfaces.WtAccount;
  10 +using Mapster;
  11 +using Microsoft.AspNetCore.Mvc;
  12 +using SqlSugar;
  13 +using System;
  14 +using System.Collections.Generic;
  15 +using System.Linq;
  16 +using System.Text;
  17 +using System.Text.RegularExpressions;
  18 +using System.Threading.Tasks;
  19 +using NCC.Extend.Entitys;
  20 +using NCC.Extend.Entitys.Dto.WtAccount;
  21 +using Yitter.IdGenerator;
  22 +using NCC.Common.Helper;
  23 +using NCC.JsonSerialization;
  24 +using NCC.Common.Model.NPOI;
  25 +using NCC.Common.Configuration;
  26 +using NCC.DataEncryption;
  27 +using NCC.ClayObject;
  28 +
  29 +namespace NCC.Extend.WtAccount
  30 +{
  31 + /// <summary>
  32 + /// 账户管理服务(独立业务模块,替代原数据字典)
  33 + /// </summary>
  34 + [ApiDescriptionSettings(Tag = "Extend", Name = "WtAccount", Order = 200)]
  35 + [Route("api/Extend/[controller]")]
  36 + public class WtAccountService : IWtAccountService, IDynamicApiController, ITransient
  37 + {
  38 + private readonly ISqlSugarRepository<WtAccountEntity> _repo;
  39 + private readonly SqlSugarScope _db;
  40 + private readonly IUserManager _userManager;
  41 +
  42 + /// <summary>
  43 + /// 初始化
  44 + /// </summary>
  45 + public WtAccountService(
  46 + ISqlSugarRepository<WtAccountEntity> repo,
  47 + IUserManager userManager)
  48 + {
  49 + _repo = repo;
  50 + _db = _repo.Context;
  51 + _userManager = userManager;
  52 + }
  53 +
  54 + /// <summary>
  55 + /// 获取账户详情
  56 + /// </summary>
  57 + [HttpGet("{id}")]
  58 + public async Task<dynamic> GetInfo(string id)
  59 + {
  60 + var entity = await _db.Queryable<WtAccountEntity>().Where(p => p.Id == id).FirstAsync();
  61 + _ = entity ?? throw NCCException.Oh(ErrorCode.COM1005);
  62 + return new WtAccountInfoOutput
  63 + {
  64 + id = entity.Id,
  65 + accountCode = entity.AccountCode,
  66 + accountName = entity.AccountName,
  67 + category = entity.Category,
  68 + status = entity.Status,
  69 + sortCode = entity.SortCode,
  70 + createTime = entity.CreateTime
  71 + };
  72 + }
  73 +
  74 + /// <summary>
  75 + /// 获取账户列表(分页)
  76 + /// </summary>
  77 + [HttpGet("")]
  78 + public async Task<dynamic> GetList([FromQuery] WtAccountListQueryInput input)
  79 + {
  80 + // MergeTable 后 OrderBy 的列名须与 Select 投影别名一致(camelCase),不能用库表列名 sort_code
  81 + var sidx = string.IsNullOrEmpty(input.sidx) ? "accountCode" : input.sidx;
  82 + var data = await _db.Queryable<WtAccountEntity>()
  83 + .WhereIF(!string.IsNullOrEmpty(input.keyword),
  84 + p => p.AccountCode.Contains(input.keyword)
  85 + || p.AccountName.Contains(input.keyword))
  86 + .WhereIF(!string.IsNullOrEmpty(input.category), p => p.Category == input.category)
  87 + .WhereIF(input.status.HasValue, p => p.Status == input.status.Value)
  88 + .Select(it => new WtAccountListOutput
  89 + {
  90 + id = it.Id,
  91 + accountCode = it.AccountCode,
  92 + accountName = it.AccountName,
  93 + category = it.Category,
  94 + status = it.Status,
  95 + sortCode = it.SortCode
  96 + })
  97 + .MergeTable()
  98 + .OrderBy(sidx + " " + input.sort)
  99 + .ToPagedListAsync(input.currentPage, input.pageSize);
  100 + return PageResult<WtAccountListOutput>.SqlSugarPageResult(data);
  101 + }
  102 +
  103 + /// <summary>
  104 + /// 获取账户下拉选项(前端 el-select 用,只返回启用账户)。
  105 + /// 若传 storeId,只返回该门店在 wt_skzhb 中关联的账户;不传则返回全部启用账户。
  106 + /// </summary>
  107 + [HttpGet("Selector")]
  108 + public async Task<dynamic> GetSelector([FromQuery] string storeId = null)
  109 + {
  110 + ISugarQueryable<WtAccountEntity> query;
  111 + if (!string.IsNullOrWhiteSpace(storeId))
  112 + {
  113 + var sid = storeId.Trim();
  114 + var accountIds = await _db.Queryable<WtSkzhbEntity>()
  115 + .Where(r => r.Ssmd == sid)
  116 + .Select(r => r.Zhmc)
  117 + .ToListAsync();
  118 + var idSet = accountIds.Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim()).Distinct().ToList();
  119 + query = _db.Queryable<WtAccountEntity>()
  120 + .Where(p => p.Status == 1 && idSet.Contains(p.Id));
  121 + }
  122 + else
  123 + {
  124 + query = _db.Queryable<WtAccountEntity>().Where(p => p.Status == 1);
  125 + }
  126 +
  127 + var list = await query
  128 + .OrderBy(p => p.AccountCode)
  129 + .Select(p => new
  130 + {
  131 + id = p.Id,
  132 + accountCode = p.AccountCode,
  133 + accountName = p.AccountName,
  134 + fullName = p.AccountName,
  135 + category = p.Category
  136 + })
  137 + .ToListAsync();
  138 + return new { list };
  139 + }
  140 +
  141 + /// <summary>
  142 + /// 新建账户
  143 + /// </summary>
  144 + [HttpPost("")]
  145 + public async Task Create([FromBody] WtAccountCrInput input)
  146 + {
  147 + if (string.IsNullOrWhiteSpace(input.accountName))
  148 + {
  149 + throw NCCException.Oh("账户名称不能为空");
  150 + }
  151 +
  152 + var entity = new WtAccountEntity
  153 + {
  154 + Id = YitIdHelper.NextId().ToString(),
  155 + AccountName = input.accountName.Trim(),
  156 + Category = string.IsNullOrWhiteSpace(input.category) ? null : input.category.Trim(),
  157 + Status = 1,
  158 + SortCode = input.sortCode ?? 0,
  159 + CreateTime = DateTime.Now
  160 + };
  161 +
  162 + if (string.IsNullOrWhiteSpace(input.accountCode))
  163 + {
  164 + var rule = input.codeRule.GetValueOrDefault(1);
  165 + entity.AccountCode = await GenerateCodeAsync(rule, entity.AccountName);
  166 + }
  167 + else
  168 + {
  169 + var manual = input.accountCode.Trim();
  170 + if (await _db.Queryable<WtAccountEntity>().AnyAsync(x => x.AccountCode == manual))
  171 + {
  172 + throw NCCException.Oh("业务编码已存在,请更换或留空自动生成");
  173 + }
  174 + entity.AccountCode = manual;
  175 + }
  176 +
  177 + var isOk = await _db.Insertable(entity).ExecuteCommandAsync();
  178 + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000);
  179 + }
  180 +
  181 + /// <summary>
  182 + /// 更新账户
  183 + /// </summary>
  184 + [HttpPut("{id}")]
  185 + public async Task Update(string id, [FromBody] WtAccountUpInput input)
  186 + {
  187 + var entity = await _db.Queryable<WtAccountEntity>().FirstAsync(p => p.Id == id);
  188 + _ = entity ?? throw NCCException.Oh(ErrorCode.COM1005);
  189 +
  190 + if (!string.IsNullOrWhiteSpace(input.accountName))
  191 + {
  192 + entity.AccountName = input.accountName.Trim();
  193 + }
  194 +
  195 + entity.Category = string.IsNullOrWhiteSpace(input.category) ? null : input.category.Trim();
  196 +
  197 + if (input.status.HasValue)
  198 + {
  199 + entity.Status = input.status.Value;
  200 + }
  201 +
  202 + if (input.sortCode.HasValue)
  203 + {
  204 + entity.SortCode = input.sortCode.Value;
  205 + }
  206 +
  207 + if (!string.IsNullOrWhiteSpace(input.accountCode))
  208 + {
  209 + var code = input.accountCode.Trim();
  210 + if (await _db.Queryable<WtAccountEntity>().AnyAsync(x => x.AccountCode == code && x.Id != id))
  211 + {
  212 + throw NCCException.Oh("业务编码已存在");
  213 + }
  214 + entity.AccountCode = code;
  215 + }
  216 +
  217 + var isOk = await _db.Updateable(entity).ExecuteCommandAsync();
  218 + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1001);
  219 + }
  220 +
  221 + /// <summary>
  222 + /// 删除账户
  223 + /// </summary>
  224 + [HttpDelete("{id}")]
  225 + public async Task Delete(string id)
  226 + {
  227 + var entity = await _db.Queryable<WtAccountEntity>().FirstAsync(p => p.Id == id);
  228 + _ = entity ?? throw NCCException.Oh(ErrorCode.COM1005);
  229 + var isOk = await _db.Deleteable<WtAccountEntity>().Where(d => d.Id == id).ExecuteCommandAsync();
  230 + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1002);
  231 + }
  232 +
  233 + /// <summary>
  234 + /// 批量删除账户
  235 + /// </summary>
  236 + [HttpPost("batchRemove")]
  237 + public async Task BatchRemove([FromBody] List<string> ids)
  238 + {
  239 + if (ids == null || ids.Count == 0) return;
  240 + try
  241 + {
  242 + _db.BeginTran();
  243 + await _db.Deleteable<WtAccountEntity>().In(d => d.Id, ids).ExecuteCommandAsync();
  244 + _db.CommitTran();
  245 + }
  246 + catch (Exception)
  247 + {
  248 + _db.RollbackTran();
  249 + throw NCCException.Oh(ErrorCode.COM1002);
  250 + }
  251 + }
  252 +
  253 + /// <summary>
  254 + /// 导出账户
  255 + /// </summary>
  256 + [HttpGet("Actions/Export")]
  257 + public async Task<dynamic> Export([FromQuery] WtAccountListQueryInput input)
  258 + {
  259 + var exportData = new List<WtAccountListOutput>();
  260 + if (input.dataType == 0)
  261 + {
  262 + var data = Clay.Object(await this.GetList(input));
  263 + exportData = data.Solidify<PageResult<WtAccountListOutput>>().list;
  264 + }
  265 + else
  266 + {
  267 + exportData = await GetNoPagingList(input);
  268 + }
  269 + List<ParamsModel> paramList = "[{\"value\":\"业务编码\",\"field\":\"accountCode\"},{\"value\":\"账户名称\",\"field\":\"accountName\"},{\"value\":\"账户分类\",\"field\":\"category\"},{\"value\":\"状态\",\"field\":\"status\"}]".ToList<ParamsModel>();
  270 + var excelconfig = new ExcelConfig();
  271 + excelconfig.FileName = "账户管理.xls";
  272 + excelconfig.HeadFont = "微软雅黑";
  273 + excelconfig.HeadPoint = 10;
  274 + excelconfig.IsAllSizeColumn = true;
  275 + excelconfig.ColumnModel = new List<ExcelColumnModel>();
  276 + var selectKeyList = input.selectKey.Split(',').ToList();
  277 + foreach (var item in selectKeyList)
  278 + {
  279 + var isExist = paramList.Find(p => p.field == item);
  280 + if (isExist != null)
  281 + {
  282 + excelconfig.ColumnModel.Add(new ExcelColumnModel() { Column = isExist.field, ExcelColumn = isExist.value });
  283 + }
  284 + }
  285 + var addPath = FileVariable.TemporaryFilePath + excelconfig.FileName;
  286 + ExcelExportHelper<WtAccountListOutput>.Export(exportData, excelconfig, addPath);
  287 + var fileName = _userManager.UserId + "|" + addPath + "|xls";
  288 + return new
  289 + {
  290 + name = excelconfig.FileName,
  291 + url = "/api/File/Download?encryption=" + DESCEncryption.Encrypt(fileName, "NCC")
  292 + };
  293 + }
  294 +
  295 + /// <summary>
  296 + /// 获取分类列表(去重)
  297 + /// </summary>
  298 + [HttpGet("Categories")]
  299 + public async Task<dynamic> GetCategories()
  300 + {
  301 + var categories = await _db.Queryable<WtAccountEntity>()
  302 + .Where(p => p.Category != null && p.Category != "")
  303 + .GroupBy(p => p.Category)
  304 + .Select(p => p.Category)
  305 + .ToListAsync();
  306 + return categories;
  307 + }
  308 +
  309 + #region 私有方法
  310 +
  311 + private async Task<List<WtAccountListOutput>> GetNoPagingList(WtAccountListQueryInput input)
  312 + {
  313 + var sidx = string.IsNullOrEmpty(input.sidx) ? "accountCode" : input.sidx;
  314 + return await _db.Queryable<WtAccountEntity>()
  315 + .WhereIF(!string.IsNullOrEmpty(input.keyword),
  316 + p => p.AccountCode.Contains(input.keyword)
  317 + || p.AccountName.Contains(input.keyword))
  318 + .WhereIF(!string.IsNullOrEmpty(input.category), p => p.Category == input.category)
  319 + .WhereIF(input.status.HasValue, p => p.Status == input.status.Value)
  320 + .Select(it => new WtAccountListOutput
  321 + {
  322 + id = it.Id,
  323 + accountCode = it.AccountCode,
  324 + accountName = it.AccountName,
  325 + category = it.Category,
  326 + status = it.Status,
  327 + sortCode = it.SortCode
  328 + })
  329 + .MergeTable()
  330 + .OrderBy(sidx + " " + input.sort)
  331 + .ToListAsync();
  332 + }
  333 +
  334 + private const string CodePrefix = "SKZH";
  335 +
  336 + private async Task<string> GenerateCodeAsync(int codeRule, string accountName)
  337 + {
  338 + if (codeRule == 2)
  339 + {
  340 + var abbr = BuildPinyinAbbreviation(accountName);
  341 + return await EnsureUniqueCodeAsync(abbr);
  342 + }
  343 +
  344 + return await NextSequentialCodeAsync();
  345 + }
  346 +
  347 + private async Task<string> NextSequentialCodeAsync()
  348 + {
  349 + var codes = await _db.Queryable<WtAccountEntity>()
  350 + .Where(x => x.AccountCode != null && x.AccountCode.StartsWith(CodePrefix))
  351 + .Select(x => x.AccountCode)
  352 + .ToListAsync();
  353 + var max = 0;
  354 + foreach (var z in codes)
  355 + {
  356 + if (z == null || z.Length <= CodePrefix.Length) continue;
  357 + var tail = z.Substring(CodePrefix.Length);
  358 + if (int.TryParse(tail, out var n) && n > max) max = n;
  359 + }
  360 + return CodePrefix + (max + 1).ToString("D5");
  361 + }
  362 +
  363 + private static string BuildPinyinAbbreviation(string text)
  364 + {
  365 + if (string.IsNullOrWhiteSpace(text)) return "ZH";
  366 + var sb = new StringBuilder();
  367 + foreach (var c in text.Trim())
  368 + {
  369 + if (c >= 0x4e00 && c <= 0x9fff)
  370 + {
  371 + var py = PinyinUtil.PinyinString(c.ToString());
  372 + if (!string.IsNullOrEmpty(py))
  373 + {
  374 + var token = py.Split(',')[0].Trim();
  375 + if (token.Length > 0 && char.IsLetter(token[0]))
  376 + sb.Append(char.ToUpperInvariant(token[0]));
  377 + }
  378 + }
  379 + else if (char.IsLetterOrDigit(c))
  380 + {
  381 + sb.Append(char.ToUpperInvariant(c));
  382 + }
  383 + }
  384 + var raw = Regex.Replace(sb.ToString(), "[^A-Z0-9]", "");
  385 + if (string.IsNullOrEmpty(raw)) return "ZH";
  386 + return raw.Length > 12 ? raw.Substring(0, 12) : raw;
  387 + }
  388 +
  389 + private async Task<string> EnsureUniqueCodeAsync(string candidate)
  390 + {
  391 + var baseCode = string.IsNullOrWhiteSpace(candidate) ? "ZH" : candidate.Trim();
  392 + var c = baseCode;
  393 + var n = 0;
  394 + while (await _db.Queryable<WtAccountEntity>().AnyAsync(x => x.AccountCode == c))
  395 + {
  396 + n++;
  397 + c = baseCode + n;
  398 + }
  399 + return c;
  400 + }
  401 +
  402 + #endregion
  403 + }
  404 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtCzdService.cs
... ... @@ -734,7 +734,7 @@ namespace NCC.Extend.WtCzd
734 734 {
735 735 await _db.Ado.ExecuteCommandAsync(
736 736 "INSERT INTO wt_sp_cost (F_Id, spbh, ck, cbj, sl, update_time) VALUES (@id, @spbh, @ck, @cbj, @sl, NOW())",
737   - new { id = $"{item.Spbh}_{warehouseId}", spbh = item.Spbh, ck = warehouseId, cbj = inCostPerUnit, sl = qty });
  737 + new { id = YitIdHelper.NextId().ToString(), spbh = item.Spbh, ck = warehouseId, cbj = inCostPerUnit, sl = qty });
738 738 }
739 739 }
740 740 }
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtMdService.cs
... ... @@ -178,7 +178,58 @@ namespace NCC.Extend.WtMd
178 178 }
179 179  
180 180 /// <summary>
181   - /// 批量删除门店管理
  181 + /// 查询 <c>wt_ck.F_ssmd</c> 中与门店主键或门店分组绑定的仓库名称(单值或逗号分隔多值均匹配)。
  182 + /// </summary>
  183 + private static (string WhereSql, object Pars) BuildSsmdMatchWhere(string sid, string grp)
  184 + {
  185 + if (string.IsNullOrWhiteSpace(grp))
  186 + {
  187 + const string sql = "(`F_ssmd` = @sid OR FIND_IN_SET(@sid, `F_ssmd`) > 0)";
  188 + return (sql, new { sid });
  189 + }
  190 +
  191 + var sqlGrp =
  192 + "( (`F_ssmd` = @sid OR FIND_IN_SET(@sid, `F_ssmd`) > 0) OR " +
  193 + "(`F_ssmd` = @grp OR FIND_IN_SET(@grp, `F_ssmd`) > 0) )";
  194 + return (sqlGrp, new { sid, grp });
  195 + }
  196 +
  197 + /// <summary>
  198 + /// 返回 <c>wt_ck</c> 中与门店主键或门店分组(<c>F_MdfzId</c>)在 <c>F_ssmd</c> 上绑定的仓库名称列表。
  199 + /// </summary>
  200 + private async Task<List<string>> GetLinkedWarehouseNamesAsync(WtMdEntity md)
  201 + {
  202 + if (md == null) return new List<string>();
  203 + var sid = md.Id?.Trim();
  204 + if (string.IsNullOrEmpty(sid)) return new List<string>();
  205 + var grp = string.IsNullOrWhiteSpace(md.MdfzId) ? null : md.MdfzId.Trim();
  206 + var (whereSql, pars) = BuildSsmdMatchWhere(sid, grp);
  207 + var names = await _db.Queryable<WtCkEntity>()
  208 + .Where(whereSql + " AND (`F_ssmd` IS NOT NULL AND TRIM(`F_ssmd`) <> '')", pars)
  209 + .Select(c => c.Mdmc)
  210 + .ToListAsync();
  211 + return names
  212 + .Where(x => !string.IsNullOrWhiteSpace(x))
  213 + .Select(x => x.Trim())
  214 + .Distinct(StringComparer.Ordinal)
  215 + .ToList();
  216 + }
  217 +
  218 + /// <summary>
  219 + /// 若存在关联仓库(所属门店指向本店或本店分组),则抛出业务异常。
  220 + /// </summary>
  221 + private async Task EnsureNoLinkedWarehousesAsync(WtMdEntity md)
  222 + {
  223 + var distinct = await GetLinkedWarehouseNamesAsync(md);
  224 + if (distinct.Count == 0) return;
  225 + var sid = md.Id?.Trim();
  226 + var mdLabel = string.IsNullOrWhiteSpace(md.Mdmc) ? sid : md.Mdmc.Trim();
  227 + throw NCCException.Oh(
  228 + $"门店「{mdLabel}」存在关联仓库({string.Join("、", distinct)}),请先在仓库管理中将所属门店解绑后再删除。");
  229 + }
  230 +
  231 + /// <summary>
  232 + /// 批量删除门店管理;任一条门店存在关联仓库则整批不删并返回汇总提示。
182 233 /// </summary>
183 234 /// <param name="ids">主键数组</param>
184 235 /// <returns></returns>
... ... @@ -188,6 +239,19 @@ namespace NCC.Extend.WtMd
188 239 var entitys = await _db.Queryable<WtMdEntity>().In(it => it.Id, ids).ToListAsync();
189 240 if (entitys.Count > 0)
190 241 {
  242 + var blocks = new List<string>();
  243 + foreach (var e in entitys)
  244 + {
  245 + var wh = await GetLinkedWarehouseNamesAsync(e);
  246 + if (wh.Count == 0) continue;
  247 + var sid = e.Id?.Trim();
  248 + var mdLabel = string.IsNullOrWhiteSpace(e.Mdmc) ? sid : e.Mdmc.Trim();
  249 + blocks.Add($"「{mdLabel}」:{string.Join("、", wh)}");
  250 + }
  251 +
  252 + if (blocks.Count > 0)
  253 + throw NCCException.Oh(
  254 + "以下门店存在关联仓库,请先在仓库管理中将所属门店解绑后再删除:" + string.Join(";", blocks));
191 255 try
192 256 {
193 257 //开启事务
... ... @@ -221,7 +285,7 @@ namespace NCC.Extend.WtMd
221 285 }
222 286  
223 287 /// <summary>
224   - /// 删除门店管理
  288 + /// 删除门店管理;若 <c>wt_ck</c> 中仍有仓库的所属门店指向该门店(或门店分组),则禁止删除。
225 289 /// </summary>
226 290 /// <returns></returns>
227 291 [HttpDelete("{id}")]
... ... @@ -229,6 +293,7 @@ namespace NCC.Extend.WtMd
229 293 {
230 294 var entity = await _db.Queryable<WtMdEntity>().FirstAsync(p => p.Id == id);
231 295 _ = entity ?? throw NCCException.Oh(ErrorCode.COM1005);
  296 + await EnsureNoLinkedWarehousesAsync(entity);
232 297 var isOk = await _db.Deleteable<WtMdEntity>().Where(d => d.Id == id).ExecuteCommandAsync();
233 298 if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1002);
234 299 }
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtSkfkChannelStatService.cs
... ... @@ -552,14 +552,14 @@ namespace NCC.Extend.WtSkfkChannelStat
552 552 var idList = ids.Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList();
553 553 if (idList.Count == 0)
554 554 return map;
555   - var rows = await _db.Queryable<DictionaryDataEntity>()
556   - .Where(d => d.DeleteMark == null && idList.Contains(d.Id))
557   - .Select(d => new { d.Id, d.FullName })
  555 + var rows = await _db.Queryable<WtAccountEntity>()
  556 + .Where(a => idList.Contains(a.Id))
  557 + .Select(a => new { a.Id, a.AccountName })
558 558 .ToListAsync();
559 559 foreach (var r in rows)
560 560 {
561 561 if (!string.IsNullOrEmpty(r.Id))
562   - map[r.Id] = r.FullName ?? "";
  562 + map[r.Id] = r.AccountName ?? "";
563 563 }
564 564  
565 565 return map;
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtSkzhbService.cs
... ... @@ -57,17 +57,16 @@ namespace NCC.Extend.WtSkzhb
57 57 [HttpGet("{id}")]
58 58 public async Task<dynamic> GetInfo(string id)
59 59 {
60   - var output = await _db.Queryable<WtSkzhbEntity>()
61   - .Where(p => p.Id == id)
62   - .Select(it => new WtSkzhbInfoOutput
  60 + var output = await _db.Queryable<WtSkzhbEntity, WtAccountEntity, DictionaryDataEntity, WtMdEntity>((sk, acc, dict, md) => new JoinQueryInfos(
  61 + JoinType.Left, sk.Zhmc == acc.Id,
  62 + JoinType.Left, sk.Zhmc == dict.Id && (dict.DeleteMark == null || dict.DeleteMark == 0),
  63 + JoinType.Left, sk.Ssmd == md.Id))
  64 + .Where((sk, acc, dict, md) => sk.Id == id)
  65 + .Select((sk, acc, dict, md) => new WtSkzhbInfoOutput
63 66 {
64   - id = it.Id,
65   - zhmc = SqlFunc.Subqueryable<DictionaryDataEntity>()
66   - .Where(d => d.Id == it.Zhmc)
67   - .Select(d => d.FullName),
68   - ssmd = SqlFunc.Subqueryable<WtMdEntity>()
69   - .Where(m => m.Id == it.Ssmd)
70   - .Select(m => m.Mdmc),
  67 + id = sk.Id,
  68 + zhmc = SqlFunc.IsNull(SqlFunc.IsNull(acc.AccountName, dict.FullName), sk.Zhmc),
  69 + ssmd = md.Mdmc,
71 70 })
72 71 .FirstAsync();
73 72 return output;
... ... @@ -81,25 +80,36 @@ namespace NCC.Extend.WtSkzhb
81 80 [HttpGet("")]
82 81 public async Task<dynamic> GetList([FromQuery] WtSkzhbListQueryInput input)
83 82 {
84   - var sidx = input.sidx == null ? "id" : input.sidx;
85   - var data = await _db.Queryable<WtSkzhbEntity>()
86   - .WhereIF(!string.IsNullOrEmpty(input.id), p => p.Id.Contains(input.id))
87   - .WhereIF(!string.IsNullOrEmpty(input.zhmc), p => p.Zhmc.Contains(input.zhmc))
88   - .WhereIF(!string.IsNullOrEmpty(input.ssmd), p => p.Ssmd.Contains(input.ssmd))
89   - .Select(it=> new WtSkzhbListOutput
  83 + input ??= new WtSkzhbListQueryInput();
  84 + var pageIndex = input.currentPage > 0 ? input.currentPage : 1;
  85 + var pageSize = input.pageSize > 0 ? input.pageSize : 50;
  86 + var sidxRaw = string.IsNullOrWhiteSpace(input.sidx) ? "id" : input.sidx.Trim();
  87 + var sortRaw = string.IsNullOrWhiteSpace(input.sort) ? "desc" : input.sort.Trim();
  88 + // MergeTable 后 OrderBy 使用输出列名;限制字段避免注入
  89 + var sidx = new[] { "id", "zhmc", "ssmd", "skzhDictId" }.Contains(sidxRaw, StringComparer.OrdinalIgnoreCase) ? sidxRaw : "id";
  90 + var sort = sortRaw.Equals("asc", StringComparison.OrdinalIgnoreCase) ? "asc" : "desc";
  91 + var ssmdEq = string.IsNullOrWhiteSpace(input.ssmd) ? null : input.ssmd.Trim();
  92 + // 不用 Select 内嵌 Subqueryable + MergeTable(SqlSugar SubResolve 会 NRE),改为 LeftJoin 拼列
  93 + var data = await _db.Queryable<WtSkzhbEntity, WtAccountEntity, DictionaryDataEntity, WtMdEntity>((sk, acc, dict, md) => new JoinQueryInfos(
  94 + JoinType.Left, sk.Zhmc == acc.Id,
  95 + JoinType.Left, sk.Zhmc == dict.Id && (dict.DeleteMark == null || dict.DeleteMark == 0),
  96 + JoinType.Left, sk.Ssmd == md.Id))
  97 + .WhereIF(!string.IsNullOrEmpty(input.id), (sk, acc, dict, md) => sk.Id.Contains(input.id))
  98 + .WhereIF(!string.IsNullOrEmpty(input.zhmc), (sk, acc, dict, md) => sk.Zhmc.Contains(input.zhmc))
  99 + .WhereIF(ssmdEq != null, (sk, acc, dict, md) => sk.Ssmd != null && (
  100 + SqlFunc.Trim(sk.Ssmd) == ssmdEq ||
  101 + sk.Ssmd.Contains(ssmdEq)))
  102 + .Select((sk, acc, dict, md) => new WtSkzhbListOutput
90 103 {
91   - id = it.Id,
92   - skzhDictId = it.Zhmc,
93   - // ✅ 账户名称:通过子查询关联字典表,将ID转换为中文名称
94   - zhmc = SqlFunc.Subqueryable<DictionaryDataEntity>()
95   - .Where(d => d.Id == it.Zhmc)
96   - .Select(d => d.FullName),
97   - // ✅ 门店:通过子查询关联门店表,将ID转换为中文名称
98   - ssmd = SqlFunc.Subqueryable<WtMdEntity>()
99   - .Where(m => m.Id == it.Ssmd)
100   - .Select(m => m.Mdmc),
101   - }).MergeTable().OrderBy(sidx+" "+input.sort).ToPagedListAsync(input.currentPage, input.pageSize);
102   - return PageResult<WtSkzhbListOutput>.SqlSugarPageResult(data);
  104 + id = sk.Id,
  105 + skzhDictId = sk.Zhmc,
  106 + zhmc = SqlFunc.IsNull(SqlFunc.IsNull(acc.AccountName, dict.FullName), sk.Zhmc),
  107 + ssmd = md.Mdmc,
  108 + })
  109 + .MergeTable()
  110 + .OrderBy(sidx + " " + sort)
  111 + .ToPagedListAsync(pageIndex, pageSize);
  112 + return PageResult<WtSkzhbListOutput>.SqlSugarPageResult(data);
103 113 }
104 114  
105 115 /// <summary>
... ... @@ -125,25 +135,32 @@ namespace NCC.Extend.WtSkzhb
125 135 [NonAction]
126 136 public async Task<dynamic> GetNoPagingList([FromQuery] WtSkzhbListQueryInput input)
127 137 {
128   - var sidx = input.sidx == null ? "id" : input.sidx;
129   - var data = await _db.Queryable<WtSkzhbEntity>()
130   - .WhereIF(!string.IsNullOrEmpty(input.id), p => p.Id.Contains(input.id))
131   - .WhereIF(!string.IsNullOrEmpty(input.zhmc), p => p.Zhmc.Contains(input.zhmc))
132   - .WhereIF(!string.IsNullOrEmpty(input.ssmd), p => p.Ssmd.Contains(input.ssmd))
133   - .Select(it=> new WtSkzhbListOutput
  138 + input ??= new WtSkzhbListQueryInput();
  139 + var sidxRaw = string.IsNullOrWhiteSpace(input.sidx) ? "id" : input.sidx.Trim();
  140 + var sortRaw = string.IsNullOrWhiteSpace(input.sort) ? "desc" : input.sort.Trim();
  141 + var sidx = new[] { "id", "zhmc", "ssmd", "skzhDictId" }.Contains(sidxRaw, StringComparer.OrdinalIgnoreCase) ? sidxRaw : "id";
  142 + var sort = sortRaw.Equals("asc", StringComparison.OrdinalIgnoreCase) ? "asc" : "desc";
  143 + var ssmdEq = string.IsNullOrWhiteSpace(input.ssmd) ? null : input.ssmd.Trim();
  144 + var data = await _db.Queryable<WtSkzhbEntity, WtAccountEntity, DictionaryDataEntity, WtMdEntity>((sk, acc, dict, md) => new JoinQueryInfos(
  145 + JoinType.Left, sk.Zhmc == acc.Id,
  146 + JoinType.Left, sk.Zhmc == dict.Id && (dict.DeleteMark == null || dict.DeleteMark == 0),
  147 + JoinType.Left, sk.Ssmd == md.Id))
  148 + .WhereIF(!string.IsNullOrEmpty(input.id), (sk, acc, dict, md) => sk.Id.Contains(input.id))
  149 + .WhereIF(!string.IsNullOrEmpty(input.zhmc), (sk, acc, dict, md) => sk.Zhmc.Contains(input.zhmc))
  150 + .WhereIF(ssmdEq != null, (sk, acc, dict, md) => sk.Ssmd != null && (
  151 + SqlFunc.Trim(sk.Ssmd) == ssmdEq ||
  152 + sk.Ssmd.Contains(ssmdEq)))
  153 + .Select((sk, acc, dict, md) => new WtSkzhbListOutput
134 154 {
135   - id = it.Id,
136   - skzhDictId = it.Zhmc,
137   - // ✅ 账户名称:通过子查询关联字典表,将ID转换为中文名称
138   - zhmc = SqlFunc.Subqueryable<DictionaryDataEntity>()
139   - .Where(d => d.Id == it.Zhmc)
140   - .Select(d => d.FullName),
141   - // ✅ 门店:通过子查询关联门店表,将ID转换为中文名称
142   - ssmd = SqlFunc.Subqueryable<WtMdEntity>()
143   - .Where(m => m.Id == it.Ssmd)
144   - .Select(m => m.Mdmc),
145   - }).MergeTable().OrderBy(sidx+" "+input.sort).ToListAsync();
146   - return data;
  155 + id = sk.Id,
  156 + skzhDictId = sk.Zhmc,
  157 + zhmc = SqlFunc.IsNull(SqlFunc.IsNull(acc.AccountName, dict.FullName), sk.Zhmc),
  158 + ssmd = md.Mdmc,
  159 + })
  160 + .MergeTable()
  161 + .OrderBy(sidx + " " + sort)
  162 + .ToListAsync();
  163 + return data;
147 164 }
148 165  
149 166 /// <summary>
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtSpService.cs
... ... @@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Mvc;
12 12 using SqlSugar;
13 13 using System;
14 14 using System.Collections.Generic;
  15 +using System.Data;
15 16 using System.Linq;
16 17 using System.Threading.Tasks;
17 18 using NCC.Extend.Entitys;
... ... @@ -37,6 +38,7 @@ namespace NCC.Extend.WtSp
37 38 private readonly ISqlSugarRepository<WtSpEntity> _wtSpRepository;
38 39 private readonly SqlSugarScope _db;
39 40 private readonly IUserManager _userManager;
  41 + private static bool _spCostCkMigrated;
40 42  
41 43 /// <summary>
42 44 /// 初始化一个<see cref="WtSpService"/>类型的新实例
... ... @@ -61,23 +63,95 @@ namespace NCC.Extend.WtSp
61 63 }
62 64  
63 65 /// <summary>
64   - /// 解析门店下属仓库 ID(<c>F_ssmd</c> 为单 ID 或逗号分隔多门店时均匹配,与品类 FIND_IN_SET 口径一致)。
  66 + /// 从门店名称得到用于匹配仓库名称(<c>F_mdmc</c>)的简称:去掉常见业态后缀,便于「景枫店」与「景枫仓」对齐。
  67 + /// </summary>
  68 + private static string StoreNameToWarehouseStem(string mdmc)
  69 + {
  70 + if (string.IsNullOrWhiteSpace(mdmc)) return "";
  71 + var s = mdmc.Trim();
  72 + var suffixes = new[]
  73 + {
  74 + "旗舰店", "专卖店", "体验店", "直营店", "加盟店", "概念店", "快闪店",
  75 + "店", "厅", "馆", "部", "行", "中心", "超市", "商场", "广场"
  76 + };
  77 + foreach (var suf in suffixes.OrderByDescending(x => x.Length))
  78 + {
  79 + if (s.EndsWith(suf, StringComparison.Ordinal) && s.Length > suf.Length)
  80 + {
  81 + s = s.Substring(0, s.Length - suf.Length).Trim();
  82 + break;
  83 + }
  84 + }
  85 +
  86 + return s;
  87 + }
  88 +
  89 + /// <summary>
  90 + /// 当 <c>wt_ck.F_ssmd</c> 未维护或与门店/分组不一致(历史删店、换主键)导致查不到仓库时,
  91 + /// 按门店名称前缀匹配 <c>F_mdmc</c>(<c>StartsWith</c> 简称)作为兜底,避免 <c>wt_sp_cost</c> 有数而列表 <c>mdkc</c> 恒为 0。
  92 + /// </summary>
  93 + private async Task<List<string>> GetWarehouseIdsByStoreNameStemAsync(string storeId)
  94 + {
  95 + if (string.IsNullOrWhiteSpace(storeId)) return new List<string>();
  96 + var mdmc = await _db.Queryable<WtMdEntity>()
  97 + .Where(m => m.Id == storeId)
  98 + .Select(m => m.Mdmc)
  99 + .FirstAsync();
  100 + var stem = StoreNameToWarehouseStem(mdmc);
  101 + if (string.IsNullOrEmpty(stem) || stem.Length < 2) return new List<string>();
  102 +
  103 + var ids = await _db.Queryable<WtCkEntity>()
  104 + .Where(c => c.Mdmc != null && c.Mdmc.StartsWith(stem))
  105 + .Select(c => c.Id)
  106 + .ToListAsync();
  107 + return ids
  108 + .Where(x => !string.IsNullOrWhiteSpace(x))
  109 + .Select(x => x.Trim())
  110 + .Distinct(StringComparer.OrdinalIgnoreCase)
  111 + .ToList();
  112 + }
  113 +
  114 + /// <summary>
  115 + /// 解析门店下属仓库 ID(<c>F_ssmd</c> 为单 ID 或逗号分隔多值时均匹配)。
  116 + /// 同时匹配<strong>门店主键</strong>与门店绑定的<strong>门店分组</strong>(<c>wt_md.F_MdfzId</c>):
  117 + /// 业务上仓库常挂在分组下,仅按门店 ID 查会漏库,导致 <c>wt_sp_cost</c> 汇总为 0。
  118 + /// 若仍无结果,再按门店名称前缀匹配仓库名称(见 <see cref="GetWarehouseIdsByStoreNameStemAsync"/>)。
65 119 /// </summary>
66 120 private async Task<List<string>> GetWarehouseIdsForStoreAsync(string xsmd)
67 121 {
68 122 var sid = xsmd?.Trim();
69 123 if (string.IsNullOrEmpty(sid)) return new List<string>();
  124 + var grp = await ResolveMdfzIdForStoreAsync(sid);
  125 + object pars;
  126 + string whereSql;
  127 + if (string.IsNullOrEmpty(grp))
  128 + {
  129 + whereSql = "(`F_ssmd` = @sid OR FIND_IN_SET(@sid, `F_ssmd`) > 0)";
  130 + pars = new { sid };
  131 + }
  132 + else
  133 + {
  134 + whereSql =
  135 + "( (`F_ssmd` = @sid OR FIND_IN_SET(@sid, `F_ssmd`) > 0) OR " +
  136 + "(`F_ssmd` = @grp OR FIND_IN_SET(@grp, `F_ssmd`) > 0) )";
  137 + pars = new { sid, grp };
  138 + }
  139 +
70 140 var ids = await _db.Queryable<WtCkEntity>()
71   - .Where("(`F_ssmd` = @sid OR FIND_IN_SET(@sid, `F_ssmd`) > 0)", new { sid })
  141 + .Where(whereSql, pars)
72 142 .Select(c => c.Id)
73 143 .ToListAsync();
74   - return ids
  144 + var list = ids
75 145 .Where(x => !string.IsNullOrWhiteSpace(x))
76 146 .Select(x => x.Trim())
77 147 .Distinct(StringComparer.OrdinalIgnoreCase)
78 148 .ToList();
  149 + if (list.Count > 0) return list;
  150 +
  151 + return await GetWarehouseIdsByStoreNameStemAsync(sid);
79 152 }
80 153  
  154 +
81 155 /// <summary>
82 156 /// 当前门店所属分组 ID(<c>wt_md.F_MdfzId</c>);非门店主键或未绑定时返回 null。
83 157 /// </summary>
... ... @@ -168,48 +242,90 @@ namespace NCC.Extend.WtSp
168 242 }
169 243  
170 244 /// <summary>
171   - /// 按门店写入列表行的 <see cref="WtSpListOutput.mdkc"/>:与商品库存汇总一致,仅按 <c>wt_sp_cost.sl</c> 汇总(不按序列号条数;无成本行则为 0)。
  245 + /// 在指定门店/分组上下文下,按 <c>wt_sp_cost</c> 汇总各商品 <c>sl</c>(与列表 <c>mdkc</c>、<c>BatchCheckStock</c> 一致)。
  246 + /// <c>wt_sp_cost.ck</c> 统一存仓库 ID(<c>MigrateSpCostCkToWarehouseId</c> 保证)。
  247 + /// 已解析出下属仓库时先只计仓库维度;仅当某商品在下属仓库合计为 0 时再回退 <c>ck=门店主键</c>,避免与误存门店行重复加计。
172 248 /// </summary>
173   - private async Task ApplyMdkcBySerialAsync(List<WtSpListOutput> resultList, string xsmd)
  249 + private async Task<Dictionary<string, int>> SumSpCostSlForStoreContextAsync(List<string> productIds, string storeIdTrimmed)
174 250 {
175   - if (resultList == null || resultList.Count == 0) return;
  251 + var costDict = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
  252 + if (productIds == null || productIds.Count == 0 || string.IsNullOrEmpty(storeIdTrimmed))
  253 + return costDict;
176 254  
177   - var productIds = resultList.Select(p => p.id).Distinct().ToList();
178   - var storeId = xsmd?.Trim();
  255 + var storeId = storeIdTrimmed.Trim();
  256 + var warehouseIds = await GetWarehouseIdsForStoreAsync(storeId);
179 257  
180   - List<string> warehouseIds = null;
181   - if (!string.IsNullOrEmpty(storeId))
  258 + if (warehouseIds != null && warehouseIds.Count > 0)
182 259 {
183   - warehouseIds = await GetWarehouseIdsForStoreAsync(storeId);
184   - if (warehouseIds.Count == 0)
  260 + var whSet = new HashSet<string>(
  261 + warehouseIds.Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim()),
  262 + StringComparer.OrdinalIgnoreCase);
  263 + var sumsWh = await _db.Queryable<WtSpCostEntity>()
  264 + .Where(c => productIds.Contains(c.Spbh) && c.Ck != null && whSet.Contains(c.Ck.Trim()))
  265 + .GroupBy(c => c.Spbh)
  266 + .Select(c => new { Spbh = c.Spbh, SumSl = SqlFunc.AggregateSum(c.Sl) })
  267 + .ToListAsync();
  268 + foreach (var row in sumsWh)
  269 + costDict[row.Spbh] = (int)(row.SumSl);
  270 +
  271 + var needStoreCk = productIds
  272 + .Where(pid =>
  273 + {
  274 + var key = pid?.Trim();
  275 + if (string.IsNullOrEmpty(key)) return false;
  276 + return !costDict.TryGetValue(key, out var n) || n == 0;
  277 + })
  278 + .ToList();
  279 + if (needStoreCk.Count > 0)
185 280 {
186   - foreach (var item in resultList)
187   - item.mdkc = "0";
188   - return;
  281 + var sumsStore = await _db.Queryable<WtSpCostEntity>()
  282 + .Where(c => needStoreCk.Contains(c.Spbh) && c.Ck == storeId)
  283 + .GroupBy(c => c.Spbh)
  284 + .Select(c => new { Spbh = c.Spbh, SumSl = SqlFunc.AggregateSum(c.Sl) })
  285 + .ToListAsync();
  286 + foreach (var row in sumsStore)
  287 + costDict[row.Spbh] = (int)(row.SumSl);
189 288 }
190 289 }
191   -
192   - var costDict = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
193   - if (warehouseIds == null)
  290 + else
194 291 {
195 292 var sums = await _db.Queryable<WtSpCostEntity>()
196   - .Where(c => productIds.Contains(c.Spbh))
  293 + .Where(c => productIds.Contains(c.Spbh) && c.Ck == storeId)
197 294 .GroupBy(c => c.Spbh)
198 295 .Select(c => new { Spbh = c.Spbh, SumSl = SqlFunc.AggregateSum(c.Sl) })
199 296 .ToListAsync();
200 297 foreach (var row in sums)
201 298 costDict[row.Spbh] = (int)(row.SumSl);
202 299 }
203   - else
  300 +
  301 + return costDict;
  302 + }
  303 +
  304 + /// <summary>
  305 + /// 按门店写入列表行的 <see cref="WtSpListOutput.mdkc"/>:与库存汇总一致,按 <c>wt_sp_cost.sl</c> 汇总(<strong>不是</strong>按序列号条数;方法名历史遗留)。
  306 + /// 口径:<c>ck</c> 为仓库主键时须落在门店下属 <c>wt_ck</c>;兼容 <c>ck</c> 误存为<strong>门店主键</strong>的旧数据;未配置门店仓库时不再整表置 0,改为仅按 <c>ck=门店Id</c> 汇总。
  307 + /// </summary>
  308 + private async Task ApplyMdkcBySerialAsync(List<WtSpListOutput> resultList, string xsmd)
  309 + {
  310 + if (resultList == null || resultList.Count == 0) return;
  311 +
  312 + var productIds = resultList.Select(p => p.id).Distinct().ToList();
  313 + var storeId = xsmd?.Trim();
  314 +
  315 + Dictionary<string, int> costDict;
  316 + if (string.IsNullOrEmpty(storeId))
204 317 {
  318 + costDict = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
205 319 var sums = await _db.Queryable<WtSpCostEntity>()
206   - .Where(c => productIds.Contains(c.Spbh) && warehouseIds.Contains(c.Ck))
  320 + .Where(c => productIds.Contains(c.Spbh))
207 321 .GroupBy(c => c.Spbh)
208 322 .Select(c => new { Spbh = c.Spbh, SumSl = SqlFunc.AggregateSum(c.Sl) })
209 323 .ToListAsync();
210 324 foreach (var row in sums)
211 325 costDict[row.Spbh] = (int)(row.SumSl);
212 326 }
  327 + else
  328 + costDict = await SumSpCostSlForStoreContextAsync(productIds, storeId);
213 329  
214 330 foreach (var item in resultList)
215 331 item.mdkc = costDict.TryGetValue(item.id, out var csum) ? csum.ToString() : "0";
... ... @@ -297,6 +413,48 @@ namespace NCC.Extend.WtSp
297 413 }
298 414  
299 415 /// <summary>
  416 + /// 一次性修复 wt_sp_cost 历史数据:ck 存仓库名称的改为仓库 ID;F_Id 为「商品_仓库」等非雪花主键的改为 YitId。
  417 + /// </summary>
  418 + private void MigrateSpCostCkToWarehouseId()
  419 + {
  420 + if (_spCostCkMigrated) return;
  421 + lock (typeof(WtSpService))
  422 + {
  423 + if (_spCostCkMigrated) return;
  424 + try
  425 + {
  426 + var affected = _db.Ado.ExecuteCommand(
  427 + @"UPDATE wt_sp_cost sc
  428 + INNER JOIN wt_ck ck ON ck.F_mdmc = sc.ck
  429 + LEFT JOIN wt_ck ck2 ON ck2.F_Id = sc.ck
  430 + SET sc.ck = ck.F_Id
  431 + WHERE ck2.F_Id IS NULL");
  432 + if (affected > 0)
  433 + Console.WriteLine($"✅ wt_sp_cost.ck 数据修复:{affected} 行由仓库名称改为仓库 ID");
  434 +
  435 + var dt = _db.Ado.GetDataTable("SELECT F_Id FROM wt_sp_cost WHERE F_Id REGEXP '[^0-9]'");
  436 + if (dt != null && dt.Rows.Count > 0)
  437 + {
  438 + var fidFixed = 0;
  439 + foreach (DataRow dr in dt.Rows)
  440 + {
  441 + var oldId = dr["F_Id"]?.ToString()?.Trim();
  442 + if (string.IsNullOrEmpty(oldId)) continue;
  443 + var newId = YitIdHelper.NextId().ToString();
  444 + fidFixed += _db.Ado.ExecuteCommand(
  445 + "UPDATE wt_sp_cost SET F_Id = @newId WHERE F_Id = @oldId",
  446 + new SugarParameter("@newId", newId), new SugarParameter("@oldId", oldId));
  447 + }
  448 + if (fidFixed > 0)
  449 + Console.WriteLine($"✅ wt_sp_cost.F_Id 数据修复:{fidFixed} 行由复合键改为雪花 ID");
  450 + }
  451 + }
  452 + catch (Exception ex) { Console.WriteLine($"⚠️ MigrateSpCostCkToWarehouseId: {ex.Message}"); }
  453 + _spCostCkMigrated = true;
  454 + }
  455 + }
  456 +
  457 + /// <summary>
300 458 /// 获取商品档案列表
301 459 /// </summary>
302 460 /// <param name="input">请求参数</param>
... ... @@ -304,6 +462,7 @@ namespace NCC.Extend.WtSp
304 462 [HttpGet("")]
305 463 public async Task<dynamic> GetList([FromQuery] WtSpListQueryInput input)
306 464 {
  465 + MigrateSpCostCkToWarehouseId();
307 466 Console.WriteLine("=== GetList方法开始执行 ===");
308 467 Console.WriteLine($"输入参数: spmc={input.spmc}, spbm={input.spbm}, xsmd={input.xsmd}");
309 468  
... ... @@ -398,7 +557,12 @@ namespace NCC.Extend.WtSp
398 557  
399 558  
400 559 var qk0 = WherePlCategoryIfAny(_db.Queryable<WtSpEntity>()
401   - .WhereIF(!string.IsNullOrEmpty(input.keyword), p => p.Spmc.Contains(input.keyword)||p.Spbm.Contains(input.keyword)||p.Dyspid.Contains(input.keyword)), input.pl);
  560 + .WhereIF(
  561 + !string.IsNullOrEmpty(input.keyword),
  562 + p => p.Spmc.Contains(input.keyword)
  563 + || p.Spbm.Contains(input.keyword)
  564 + || (!SqlFunc.IsNullOrEmpty(p.Dyspid) && p.Dyspid.Contains(input.keyword))),
  565 + input.pl);
402 566 var qk1 = await ApplyXsmdFilterAsync(qk0, input.xsmd);
403 567 var data = await qk1
404 568 .Select(it=> new WtSpListOutput
... ... @@ -882,10 +1046,6 @@ namespace NCC.Extend.WtSp
882 1046 try
883 1047 {
884 1048 var storeId = input.StoreId.Trim();
885   - var warehouseIds = await GetWarehouseIdsForStoreAsync(storeId);
886   -
887   - if (warehouseIds == null || warehouseIds.Count == 0)
888   - return new { success = false, msg = "该门店下没有关联的仓库" };
889 1049  
890 1050 var spbmList = input.Items.Select(i => i.Spbm).Where(s => !string.IsNullOrEmpty(s)).Distinct().ToList();
891 1051  
... ... @@ -896,13 +1056,7 @@ namespace NCC.Extend.WtSp
896 1056  
897 1057 var productIds = products.Select(p => p.Id).ToList();
898 1058  
899   - var costSums = await _db.Queryable<WtSpCostEntity>()
900   - .Where(c => productIds.Contains(c.Spbh) && warehouseIds.Contains(c.Ck))
901   - .GroupBy(c => c.Spbh)
902   - .Select(c => new { Spbh = c.Spbh, SumSl = SqlFunc.AggregateSum(c.Sl) })
903   - .ToListAsync();
904   -
905   - var stockDict = costSums.ToDictionary(x => x.Spbh, x => (int)(x.SumSl));
  1059 + var stockDict = await SumSpCostSlForStoreContextAsync(productIds, storeId);
906 1060  
907 1061 var results = input.Items.Select(item =>
908 1062 {
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtXlhService.cs
... ... @@ -49,6 +49,46 @@ namespace NCC.Extend.WtXlh
49 49 }
50 50  
51 51 /// <summary>
  52 + /// 按完整序列号查询关联单据流水(出货、退货等),按单据日期升序,便于查看单条序列号全链路。
  53 + /// </summary>
  54 + /// <param name="xlh">完整序列号(精确匹配,区分大小写与数据库一致)</param>
  55 + /// <param name="currentPage">页码</param>
  56 + /// <param name="pageSize">每页条数,最大 200</param>
  57 + [HttpGet("SerialTrace")]
  58 + public async Task<dynamic> GetSerialTrace([FromQuery] string xlh, [FromQuery] int currentPage = 1, [FromQuery] int pageSize = 100)
  59 + {
  60 + var key = xlh?.Trim();
  61 + if (string.IsNullOrEmpty(key))
  62 + throw NCCException.Bah("请输入序列号");
  63 +
  64 + if (currentPage < 1) currentPage = 1;
  65 + if (pageSize < 1) pageSize = 20;
  66 + if (pageSize > 200) pageSize = 200;
  67 +
  68 + var querySql = _db.Queryable<WtXlhEntity, WtSpEntity, WtXsckdEntity>((it, sp, xs) => it.Spbh == sp.Id && it.Djbh == xs.Id)
  69 + .Where((it, sp, xs) => it.Xlh == key);
  70 +
  71 + var data = await querySql
  72 + .Select((it, sp, xs) => new WtXlhListOutput
  73 + {
  74 + id = it.Id,
  75 + xlh = it.Xlh,
  76 + spbh = it.Spbh,
  77 + djbh = it.Djbh,
  78 + djlx = it.Djlx,
  79 + zt = it.Zt,
  80 + spmc = sp.Spmc,
  81 + djrq = SqlFunc.ToDate(xs.Djrq),
  82 + pp = SqlFunc.Subqueryable<WtPpEntity>().Where(u => u.Id == sp.Pp).Select(u => u.Ppmc)
  83 + })
  84 + .MergeTable()
  85 + .OrderBy("djrq asc")
  86 + .ToPagedListAsync(currentPage, pageSize);
  87 +
  88 + return PageResult<WtXlhListOutput>.SqlSugarPageResult(data);
  89 + }
  90 +
  91 + /// <summary>
52 92 /// 获取序列号管理
53 93 /// </summary>
54 94 /// <param name="id">参数</param>
... ... @@ -76,8 +116,7 @@ namespace NCC.Extend.WtXlh
76 116 .WhereIF(!string.IsNullOrEmpty(input.djbh), it => it.Djbh.Contains(input.djbh))
77 117 .WhereIF(!string.IsNullOrEmpty(input.djlx), it => it.Djlx.Contains(input.djlx))
78 118 .WhereIF(!string.IsNullOrEmpty(input.zt), it => it.Zt.Contains(input.zt));
79   - Console.WriteLine(query_sql.ToSql());
80   -
  119 +
81 120 var data =await query_sql.Select((it,sp,xs)=> new WtXlhListOutput
82 121 {
83 122 id = it.Id,
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtXsckdService.cs
... ... @@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Authorization;
12 12 using SqlSugar;
13 13 using System;
14 14 using System.Collections.Generic;
  15 +using System.Data;
15 16 using System.Linq;
16 17 using System.Text.RegularExpressions;
17 18 using System.Threading;
... ... @@ -60,6 +61,52 @@ namespace NCC.Extend.WtXsckd
60 61 private static bool _bjhcbColumnChecked;
61 62 private static bool _fkmxColumnChecked;
62 63 private static bool _syPchColumnChecked;
  64 + private static bool _spCostCkMigrated;
  65 +
  66 + /// <summary>
  67 + /// 一次性修复 wt_sp_cost 历史数据:ck 存仓库名称的改为仓库 ID;F_Id 为「商品_仓库」等非雪花主键的改为 YitId。
  68 + /// </summary>
  69 + private void MigrateSpCostCkToWarehouseId()
  70 + {
  71 + if (_spCostCkMigrated) return;
  72 + lock (typeof(WtXsckdService))
  73 + {
  74 + if (_spCostCkMigrated) return;
  75 + try
  76 + {
  77 + var affected = _db.Ado.ExecuteCommand(
  78 + @"UPDATE wt_sp_cost sc
  79 + INNER JOIN wt_ck ck ON ck.F_mdmc = sc.ck
  80 + LEFT JOIN wt_ck ck2 ON ck2.F_Id = sc.ck
  81 + SET sc.ck = ck.F_Id
  82 + WHERE ck2.F_Id IS NULL");
  83 + if (affected > 0)
  84 + Console.WriteLine($"✅ wt_sp_cost.ck 数据修复:{affected} 行由仓库名称改为仓库 ID");
  85 +
  86 + var dt = _db.Ado.GetDataTable("SELECT F_Id FROM wt_sp_cost WHERE F_Id REGEXP '[^0-9]'");
  87 + if (dt != null && dt.Rows.Count > 0)
  88 + {
  89 + var fidFixed = 0;
  90 + foreach (DataRow dr in dt.Rows)
  91 + {
  92 + var oldId = dr["F_Id"]?.ToString()?.Trim();
  93 + if (string.IsNullOrEmpty(oldId)) continue;
  94 + var newId = YitIdHelper.NextId().ToString();
  95 + fidFixed += _db.Ado.ExecuteCommand(
  96 + "UPDATE wt_sp_cost SET F_Id = @newId WHERE F_Id = @oldId",
  97 + new SugarParameter("@newId", newId), new SugarParameter("@oldId", oldId));
  98 + }
  99 + if (fidFixed > 0)
  100 + Console.WriteLine($"✅ wt_sp_cost.F_Id 数据修复:{fidFixed} 行由复合键改为雪花 ID");
  101 + }
  102 + }
  103 + catch (Exception ex)
  104 + {
  105 + Console.WriteLine($"⚠️ MigrateSpCostCkToWarehouseId: {ex.Message}");
  106 + }
  107 + _spCostCkMigrated = true;
  108 + }
  109 + }
63 110  
64 111 /// <summary>
65 112 /// 确保收银批次号列存在(同一次结账拆单关联)
... ... @@ -377,6 +424,131 @@ namespace NCC.Extend.WtXsckd
377 424 }
378 425  
379 426 /// <summary>
  427 + /// 删除销售类出库单(销售出库单/零售单/预售出库单)时冲回创建时产生的会员消费送积分、积分抵扣、余额支付;
  428 + /// 同时删除导购提成记录(wt_dgtchsb)。与 Create 中写入逻辑对称。
  429 + /// </summary>
  430 + private async Task TryReverseSalesOutboundMemberAndCommissionAsync(WtXsckdEntity entity, string reasonTag = "删除单据")
  431 + {
  432 + if (entity == null) return;
  433 + if (entity.Djlx != "销售出库单" && entity.Djlx != "零售单" && entity.Djlx != "预售出库单") return;
  434 +
  435 + // 导购提成(与 Update 中先删除再重建逻辑一致)
  436 + try
  437 + {
  438 + if (entity.Djlx == "销售出库单" || entity.Djlx == "零售单")
  439 + {
  440 + await _db.Deleteable<WtDgtchsbEntity>().Where(t => t.Djbh == entity.Id).ExecuteCommandAsync();
  441 + Console.WriteLine($"✅ {reasonTag}删除导购提成: 单{entity.Id}");
  442 + }
  443 + }
  444 + catch (Exception ex)
  445 + {
  446 + Console.WriteLine($"⚠️ {reasonTag}删除导购提成失败(不影响删除): {ex.Message}");
  447 + }
  448 +
  449 + if (string.IsNullOrEmpty(entity.Kh)) return;
  450 +
  451 + try
  452 + {
  453 + // 冲回消费送积分
  454 + if (entity.Skje > 0)
  455 + {
  456 + var points = (int)Math.Floor(entity.Skje);
  457 + if (points > 0)
  458 + {
  459 + await _db.Insertable(new WtHyJfEntity
  460 + {
  461 + Id = YitIdHelper.NextId().ToString(),
  462 + Jfgz = $"{reasonTag}冲回消费送积分",
  463 + Jfyxq = 0,
  464 + Jf = (-points).ToString(),
  465 + JfUserId = entity.Kh,
  466 + Jfsj = DateTime.Now
  467 + }).ExecuteCommandAsync();
  468 + Console.WriteLine($"✅ {reasonTag}冲回消费送积分: 会员{entity.Kh}, -{points}积分");
  469 + }
  470 + }
  471 +
  472 + // 退回积分抵扣
  473 + var pointsDeductYuan = ParsePointsDeductYuanFromFkmxSkmx(entity.Fkmx, entity.Skmx);
  474 + if (pointsDeductYuan > 0)
  475 + {
  476 + var pointsToReturn = (int)Math.Ceiling(pointsDeductYuan * 100m);
  477 + await _db.Insertable(new WtHyJfEntity
  478 + {
  479 + Id = YitIdHelper.NextId().ToString(),
  480 + Jfgz = $"{reasonTag}退回积分抵扣",
  481 + Jfyxq = 0,
  482 + Jf = pointsToReturn.ToString(),
  483 + JfUserId = entity.Kh,
  484 + Jfsj = DateTime.Now
  485 + }).ExecuteCommandAsync();
  486 + Console.WriteLine($"✅ {reasonTag}退回积分抵扣: 会员{entity.Kh}, +{pointsToReturn}积分");
  487 + }
  488 +
  489 + // 退回余额支付
  490 + var balYuan = ParseBalanceConsumeYuanFromFkmxSkmx(entity.Fkmx, entity.Skmx);
  491 + if (balYuan > 0)
  492 + {
  493 + await InsertMemberBalanceLedgerAsync(entity.Kh, -balYuan,
  494 + $"{entity.Djlx}{entity.Id}{reasonTag}退回余额支付");
  495 + Console.WriteLine($"✅ {reasonTag}退回余额支付: 会员{entity.Kh}, ¥{balYuan}");
  496 + }
  497 + }
  498 + catch (Exception ex)
  499 + {
  500 + Console.WriteLine($"⚠️ {reasonTag}冲回会员影响失败(不影响删除): {ex.Message}");
  501 + }
  502 + }
  503 +
  504 + /// <summary>
  505 + /// 删除退货单(销售退货单/预售退货单/委托代销退货单)时,将创建时恢复为在库的序列号还原为已售出状态。
  506 + /// 利用 wt_xlh 中 zt="退货入库" 的跟踪记录定位被恢复的序列号(须在 DeleteWtXlhTrackingForDocumentAsync 之前调用)。
  507 + /// 与 ApplySalesReturnSerialRestoreForEntityAsync 对称。
  508 + /// </summary>
  509 + private async Task RevertSerialNumbersForDeletedReturnAsync(WtXsckdEntity returnEntity)
  510 + {
  511 + if (returnEntity == null) return;
  512 + if (returnEntity.Djlx != "销售退货单" && returnEntity.Djlx != "预售退货单"
  513 + && !returnEntity.Djlx.Contains("委托代销退货单")) return;
  514 +
  515 + var origId = returnEntity.Ycddh;
  516 + if (string.IsNullOrEmpty(origId))
  517 + origId = TryParseYcddhFromRemark(returnEntity.Bz);
  518 +
  519 + // 从 wt_xlh 找到本退货单「退货入库」的序列号列表
  520 + var xlhRecords = await _db.Queryable<WtXlhEntity>()
  521 + .Where(x => x.Djbh == returnEntity.Id && x.Zt == "退货入库")
  522 + .Select(x => new { x.Xlh, x.Spbh })
  523 + .ToListAsync();
  524 +
  525 + if (xlhRecords == null || xlhRecords.Count == 0) return;
  526 +
  527 + var serialNumbers = xlhRecords
  528 + .Where(x => !string.IsNullOrWhiteSpace(x.Xlh))
  529 + .Select(x => x.Xlh.Trim())
  530 + .Distinct(StringComparer.OrdinalIgnoreCase)
  531 + .ToList();
  532 +
  533 + if (serialNumbers.Count == 0) return;
  534 +
  535 + // 将这些序列号还原为已售出状态(OutDjbh 指回原出库单,与出库时写入一致)
  536 + await _db.Updateable<WtSerialNumberEntity>()
  537 + .SetColumns(it => new WtSerialNumberEntity
  538 + {
  539 + Status = 1,
  540 + OutDjbh = origId ?? "",
  541 + OutDjlx = returnEntity.Djlx == "销售退货单" ? "销售出库单"
  542 + : (returnEntity.Djlx == "预售退货单" ? "预售出库单" : "委托代销发货单"),
  543 + OutTime = DateTime.Now
  544 + })
  545 + .Where(it => serialNumbers.Contains(it.SerialNumber) && it.Status == 0)
  546 + .ExecuteCommandAsync();
  547 +
  548 + Console.WriteLine($"✅ 删除退货单{returnEntity.Id}:已将 {serialNumbers.Count} 条序列号还原为已售出(原单{origId})");
  549 + }
  550 +
  551 + /// <summary>
380 552 /// 确保原价金额列存在(迁移)
381 553 /// </summary>
382 554 private void EnsureYdjeColumn()
... ... @@ -591,6 +763,200 @@ namespace NCC.Extend.WtXsckd
591 763 }
592 764  
593 765 /// <summary>
  766 + /// 将门店主键或仓库主键展开为仓库 ID 列表,用于 <c>wt_sp_cost</c> / <c>wt_serial_number</c> 操作。
  767 + /// 与 <c>WtSpService.GetWarehouseIdsForStoreAsync</c> 保持一致的解析口径:
  768 + /// 支持 <c>FIND_IN_SET</c>(逗号分隔的 <c>F_ssmd</c>)与门店分组 <c>F_MdfzId</c>。
  769 + /// </summary>
  770 + private async Task<List<string>> ResolveWarehouseIdsForSpCostFromStoreOrCkAsync(string storeOrWarehouseId)
  771 + {
  772 + if (string.IsNullOrWhiteSpace(storeOrWarehouseId)) return new List<string>();
  773 + var raw = storeOrWarehouseId.Trim();
  774 +
  775 + string grp = null;
  776 + var mdRow = await _db.Queryable<WtMdEntity>()
  777 + .Where(m => m.Id == raw)
  778 + .Select(m => new { m.MdfzId })
  779 + .FirstAsync();
  780 + if (mdRow != null) grp = mdRow?.MdfzId;
  781 +
  782 + List<string> ids;
  783 + if (!string.IsNullOrEmpty(grp))
  784 + {
  785 + ids = await _db.Ado.SqlQueryAsync<string>(
  786 + "SELECT F_Id FROM wt_ck WHERE F_Id = @sid " +
  787 + "OR (`F_ssmd` = @sid OR FIND_IN_SET(@sid, `F_ssmd`) > 0) " +
  788 + "OR (`F_ssmd` = @grp OR FIND_IN_SET(@grp, `F_ssmd`) > 0)",
  789 + new { sid = raw, grp });
  790 + }
  791 + else
  792 + {
  793 + ids = await _db.Ado.SqlQueryAsync<string>(
  794 + "SELECT F_Id FROM wt_ck WHERE F_Id = @sid " +
  795 + "OR `F_ssmd` = @sid OR FIND_IN_SET(@sid, `F_ssmd`) > 0",
  796 + new { sid = raw });
  797 + }
  798 +
  799 + var list = ids?
  800 + .Where(x => !string.IsNullOrWhiteSpace(x))
  801 + .Select(x => x.Trim())
  802 + .Distinct(StringComparer.OrdinalIgnoreCase)
  803 + .ToList() ?? new List<string>();
  804 + if (list.Count > 0) return list;
  805 +
  806 + var wid = await ResolveWarehouseIdForSerialAsync(raw);
  807 + return string.IsNullOrWhiteSpace(wid) ? new List<string>() : new List<string> { wid.Trim() };
  808 + }
  809 +
  810 + /// <summary>
  811 + /// 删除与某出库单关联的 <c>wt_xlh</c> 跟踪行(删单或反审恢复序列号前调用,避免列表残留)。
  812 + /// </summary>
  813 + private async Task DeleteWtXlhTrackingForDocumentAsync(string djbh)
  814 + {
  815 + if (string.IsNullOrWhiteSpace(djbh)) return;
  816 + await _db.Deleteable<WtXlhEntity>().Where(x => x.Djbh == djbh).ExecuteCommandAsync();
  817 + }
  818 +
  819 + /// <summary>
  820 + /// 向 <c>wt_xlh</c> 写入跟踪行(出货、退货等);同一 <c>djbh + xlh</c> 已存在则跳过,可重复调用。
  821 + /// </summary>
  822 + private async Task InsertWtXlhDistinctAsync(string djbh, string djlx, string spbh, IEnumerable<string> xlhs, string zt)
  823 + {
  824 + if (string.IsNullOrWhiteSpace(djbh) || string.IsNullOrWhiteSpace(spbh)) return;
  825 + if (string.IsNullOrWhiteSpace(zt)) zt = "已出库";
  826 + var list = xlhs?
  827 + .Where(s => !string.IsNullOrWhiteSpace(s))
  828 + .Select(s => s.Trim())
  829 + .Distinct(StringComparer.OrdinalIgnoreCase)
  830 + .ToList() ?? new List<string>();
  831 + if (list.Count == 0) return;
  832 +
  833 + var existing = await _db.Queryable<WtXlhEntity>()
  834 + .Where(x => x.Djbh == djbh && list.Contains(x.Xlh))
  835 + .Select(x => x.Xlh)
  836 + .ToListAsync();
  837 + var existingSet = new HashSet<string>(
  838 + existing.Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim()),
  839 + StringComparer.OrdinalIgnoreCase);
  840 + var toAdd = list.Where(x => !existingSet.Contains(x)).ToList();
  841 + if (toAdd.Count == 0) return;
  842 +
  843 + var rows = toAdd.Select(xlh => new WtXlhEntity
  844 + {
  845 + Id = YitIdHelper.NextId().ToString(),
  846 + Xlh = xlh,
  847 + Spbh = spbh,
  848 + Djbh = djbh,
  849 + Djlx = djlx ?? "",
  850 + Zt = zt
  851 + }).ToList();
  852 + await _db.Insertable(rows).ExecuteCommandAsync();
  853 + }
  854 +
  855 + /// <summary>
  856 + /// 根据 <c>wt_serial_number</c> 中已出库(<c>status=1</c> 且 <c>out_djbh</c> 为本单)的记录,补全 <c>wt_xlh</c> 序列号跟踪表,
  857 + /// 与 <see cref="WtXlhService"/> 列表(联查 <c>wt_xsckd</c>)一致;幂等,已存在同单同序列号则跳过。
  858 + /// </summary>
  859 + private async Task SyncWtXlhOutboundFromSerialTableAsync(string djbh, string djlx, string spbh)
  860 + {
  861 + if (string.IsNullOrWhiteSpace(djbh) || string.IsNullOrWhiteSpace(spbh)) return;
  862 + var outSn = await _db.Queryable<WtSerialNumberEntity>()
  863 + .Where(s => s.OutDjbh == djbh && s.Spbh == spbh && s.Status == 1)
  864 + .Select(s => s.SerialNumber)
  865 + .ToListAsync();
  866 + if (outSn.Count == 0) return;
  867 + await InsertWtXlhDistinctAsync(djbh, djlx, spbh, outSn, "已出库");
  868 + }
  869 +
  870 + /// <summary>
  871 + /// 销售类建单后补齐 <c>wt_xlh</c>:先按请求明细中的 <c>selectedSerialNumbers</c> 写入(收银台已选序列号但
  872 + /// <c>wt_serial_number.in_warehouse</c> 与门店/仓库解析不一致时,原逻辑会 <c>continue</c> 导致未更新序列号池、跟踪表也为空),
  873 + /// 再按库表 <c>out_djbh</c> 同步 FIFO 等已落库的出库记录。幂等。
  874 + /// </summary>
  875 + private async Task EnsureWtXlhForSalesOutboundCreateAsync(
  876 + string djbh,
  877 + string djlx,
  878 + List<WtXsckdMxCrInput> inputMxList,
  879 + List<WtXsckdMxEntity> mxList)
  880 + {
  881 + if (string.IsNullOrWhiteSpace(djbh) || mxList == null || mxList.Count == 0) return;
  882 + for (var i = 0; i < mxList.Count; i++)
  883 + {
  884 + var detail = mxList[i];
  885 + if (string.IsNullOrEmpty(detail?.Spbh)) continue;
  886 + var inputDetail = inputMxList != null && inputMxList.Count > i ? inputMxList[i] : null;
  887 + var sel = inputDetail?.selectedSerialNumbers?
  888 + .Where(s => !string.IsNullOrWhiteSpace(s))
  889 + .Select(s => s.Trim())
  890 + .Distinct(StringComparer.OrdinalIgnoreCase)
  891 + .ToList() ?? new List<string>();
  892 + if (sel.Count > 0)
  893 + await InsertWtXlhDistinctAsync(djbh, djlx, detail.Spbh, sel, "已出库");
  894 + await SyncWtXlhOutboundFromSerialTableAsync(djbh, djlx, detail.Spbh);
  895 + }
  896 + }
  897 +
  898 + /// <summary>
  899 + /// 退货单保存后补齐 <c>wt_xlh</c>「退货入库」行:<see cref="ApplySalesReturnSerialRestoreForEntityAsync"/> 依赖
  900 + /// <c>wt_serial_number.out_djbh</c> 指向原出库单;若出货时仅写入 <c>wt_xlh</c> 而序列号池未写 <c>out_djbh</c>,则回库为 0 且无退货跟踪。
  901 + /// 此时按<strong>原单</strong>在 <c>wt_xlh</c> 中「已出库」记录 FIFO 与退货数量补写;请求体带 <c>selectedSerialNumbers</c> 时优先使用。
  902 + /// 同一原单多行同商品共用队列,避免重复分配序列号。
  903 + /// </summary>
  904 + private async Task EnsureWtXlhAfterSalesReturnCreateAsync(
  905 + WtXsckdEntity header,
  906 + List<WtXsckdMxCrInput> inputMxList,
  907 + List<WtXsckdMxEntity> mxList,
  908 + string returnDocId)
  909 + {
  910 + if (header == null || string.IsNullOrWhiteSpace(returnDocId) || mxList == null || mxList.Count == 0) return;
  911 + var lx = header.Djlx ?? "";
  912 + if (lx != "销售退货单" && lx != "预售退货单" && !lx.Contains("委托代销退货单")) return;
  913 +
  914 + var pools = new Dictionary<string, Queue<string>>(StringComparer.Ordinal);
  915 +
  916 + for (var i = 0; i < mxList.Count; i++)
  917 + {
  918 + var detail = mxList[i];
  919 + if (string.IsNullOrEmpty(detail?.Spbh) || !int.TryParse(detail.Sl, out var slVal) || slVal <= 0)
  920 + continue;
  921 +
  922 + var orig = ResolveOriginalOutboundDjbhForSalesReturn(detail, header, returnDocId);
  923 + if (string.IsNullOrEmpty(orig)) continue;
  924 +
  925 + var inputDetail = inputMxList != null && inputMxList.Count > i ? inputMxList[i] : null;
  926 + var fromInput = inputDetail?.selectedSerialNumbers?
  927 + .Where(s => !string.IsNullOrWhiteSpace(s))
  928 + .Select(s => s.Trim())
  929 + .Distinct(StringComparer.OrdinalIgnoreCase)
  930 + .ToList() ?? new List<string>();
  931 + if (fromInput.Count > 0)
  932 + {
  933 + var use = fromInput.Count <= slVal ? fromInput : fromInput.Take(slVal).ToList();
  934 + await InsertWtXlhDistinctAsync(returnDocId, lx, detail.Spbh, use, "退货入库");
  935 + continue;
  936 + }
  937 +
  938 + var poolKey = orig + "\u001f" + detail.Spbh;
  939 + if (!pools.TryGetValue(poolKey, out var q))
  940 + {
  941 + var rows = await _db.Queryable<WtXlhEntity>()
  942 + .Where(x => x.Djbh == orig && x.Spbh == detail.Spbh &&
  943 + (x.Zt == "已出库" || SqlFunc.IsNullOrEmpty(x.Zt)))
  944 + .OrderBy(x => x.Id)
  945 + .Select(x => x.Xlh)
  946 + .ToListAsync();
  947 + q = new Queue<string>(rows.Where(x => !string.IsNullOrWhiteSpace(x)));
  948 + pools[poolKey] = q;
  949 + }
  950 +
  951 + var consume = new List<string>();
  952 + while (consume.Count < slVal && q.Count > 0)
  953 + consume.Add(q.Dequeue());
  954 + if (consume.Count > 0)
  955 + await InsertWtXlhDistinctAsync(returnDocId, lx, detail.Spbh, consume, "退货入库");
  956 + }
  957 + }
  958 +
  959 + /// <summary>
594 960 /// 销售/预售/委托代销退货单:将原单已出库序列号恢复为在库(按主表原单号纠正明细 djbh)。幂等。
595 961 /// </summary>
596 962 /// <returns>成功更新为在库的序列号条数</returns>
... ... @@ -645,6 +1011,8 @@ namespace NCC.Extend.WtXsckd
645 1011 .ExecuteCommandAsync();
646 1012  
647 1013 total += updateCount;
  1014 + if (updateCount > 0)
  1015 + await InsertWtXlhDistinctAsync(returnDocId, header.Djlx ?? "", detail.Spbh, toUpdate, "退货入库");
648 1016 }
649 1017  
650 1018 return total;
... ... @@ -1036,6 +1404,7 @@ namespace NCC.Extend.WtXsckd
1036 1404 EnsureYcddhColumn();
1037 1405 EnsureYtWtfhdColumn();
1038 1406 EnsureSyPchColumn();
  1407 + MigrateSpCostCkToWarehouseId();
1039 1408 var entity = await _db.Queryable<WtXsckdEntity>().FirstAsync(p => p.Id == id);
1040 1409 _ = entity ?? throw NCCException.Oh(ErrorCode.COM1005);
1041 1410 var output = entity.Adapt<WtXsckdInfoOutput>();
... ... @@ -1980,7 +2349,6 @@ namespace NCC.Extend.WtXsckd
1980 2349 // 将字符串类型的Sl转换为int
1981 2350 if (!string.IsNullOrEmpty(detail.Spbh) && int.TryParse(detail.Sl, out int slValue) && slValue > 0)
1982 2351 {
1983   - // 确定出库门店(优先使用明细的ckck,否则使用主表的cjck)
1984 2352 var outStoreId = !string.IsNullOrEmpty(detail.Ckck) ? detail.Ckck : entity.Cjck;
1985 2353  
1986 2354 if (string.IsNullOrEmpty(outStoreId))
... ... @@ -1989,15 +2357,9 @@ namespace NCC.Extend.WtXsckd
1989 2357 continue;
1990 2358 }
1991 2359  
1992   - // 门店下属仓库;兼容仓库主键误填在 ckck 的情况(与采购退货明细一致)
1993   - var warehouseIds = await _db.Queryable<WtCkEntity>()
1994   - .Where(c => c.Ssmd == outStoreId || c.Id == outStoreId)
1995   - .Select(c => c.Id)
1996   - .ToListAsync();
1997   - if (warehouseIds == null || warehouseIds.Count == 0)
1998   - {
1999   - warehouseIds = new List<string> { outStoreId };
2000   - }
  2360 + // 序列号操作只用仓库 ID(wt_serial_number.in_warehouse 存的是 ID)
  2361 + var warehouseIds = await ResolveWarehouseIdsForSpCostFromStoreOrCkAsync(outStoreId);
  2362 + if (warehouseIds.Count == 0) warehouseIds = new List<string> { outStoreId };
2001 2363  
2002 2364 var selectedSerials = inputDetail?.selectedSerialNumbers?
2003 2365 .Where(s => !string.IsNullOrWhiteSpace(s))
... ... @@ -2059,9 +2421,16 @@ namespace NCC.Extend.WtXsckd
2059 2421 .ExecuteCommandAsync();
2060 2422  
2061 2423 Console.WriteLine($"✅ 商品 {detail.Spmc} 已出库序列号 {updated} 条(指定或 FIFO)");
  2424 + await SyncWtXlhOutboundFromSerialTableAsync(newEntity.Id, input.djlx, detail.Spbh);
2062 2425 }
2063 2426 }
2064 2427 }
  2428 +
  2429 + await EnsureWtXlhForSalesOutboundCreateAsync(
  2430 + newEntity.Id,
  2431 + input.djlx,
  2432 + input.wtXsckdMxList,
  2433 + wtXsckdMxEntityList);
2065 2434 }
2066 2435 // ✅ 销售/预售/委托代销退货单:按原单号恢复在库序列号
2067 2436 else if (input.djlx == "销售退货单" || input.djlx == "预售退货单" || input.djlx == "委托代销退货单")
... ... @@ -2071,6 +2440,11 @@ namespace NCC.Extend.WtXsckd
2071 2440 {
2072 2441 var n = await ApplySalesReturnSerialRestoreForEntityAsync(newEntity, wtXsckdMxEntityList, newEntity.Id);
2073 2442 Console.WriteLine($"✅ 退货序列号恢复合计 {n} 条");
  2443 + await EnsureWtXlhAfterSalesReturnCreateAsync(
  2444 + newEntity,
  2445 + input.wtXsckdMxList,
  2446 + wtXsckdMxEntityList,
  2447 + newEntity.Id);
2074 2448 }
2075 2449 }
2076 2450 // ✅ 处理采购退货单:扣减在库序列号(Status 0 -> 1)
... ... @@ -2097,16 +2471,10 @@ namespace NCC.Extend.WtXsckd
2097 2471 {
2098 2472 throw new Exception($"商品 {detail.Spmc} 未指定出库仓库,无法处理采购退货序列号");
2099 2473 }
2100   -
2101   - var warehouseIds = await _db.Queryable<WtCkEntity>()
2102   - .Where(c => c.Ssmd == outStoreId || c.Id == outStoreId)
2103   - .Select(c => c.Id)
2104   - .ToListAsync();
2105   - if (warehouseIds == null || warehouseIds.Count == 0)
2106   - {
2107   - warehouseIds = new List<string> { outStoreId };
2108   - }
2109   -
  2474 +
  2475 + var warehouseIds = await ResolveWarehouseIdsForSpCostFromStoreOrCkAsync(outStoreId);
  2476 + if (warehouseIds.Count == 0) warehouseIds = new List<string> { outStoreId };
  2477 +
2110 2478 var selectedSerials = inputDetail?.selectedSerialNumbers?
2111 2479 .Where(s => !string.IsNullOrWhiteSpace(s))
2112 2480 .Select(s => s.Trim())
... ... @@ -2157,6 +2525,7 @@ namespace NCC.Extend.WtXsckd
2157 2525 })
2158 2526 .Where(it => serialsToOut.Contains(it.SerialNumber))
2159 2527 .ExecuteCommandAsync();
  2528 + await SyncWtXlhOutboundFromSerialTableAsync(newEntity.Id, input.djlx, detail.Spbh);
2160 2529 }
2161 2530 }
2162 2531 }
... ... @@ -2521,15 +2890,26 @@ namespace NCC.Extend.WtXsckd
2521 2890 {
2522 2891 _db.BeginTran();
2523 2892  
2524   - // 逐单回退成本;退货单同步冲回会员账(审核不通过已冲回的跳过)
  2893 + // 逐单回退成本/积分/余额/提成/序列号
2525 2894 foreach (var entity in entitys)
2526 2895 {
2527   - if ((entity.Djlx == "销售退货单" || entity.Djlx == "预售退货单")
2528   - && !string.Equals(entity.Djzt, "审核不通过", StringComparison.Ordinal))
2529   - await TryReverseReturnMemberRefundAsync(entity, "删除单据");
2530   - if (IsStockOutboundDocumentForSerialRevert(entity.Djlx))
2531   - await RevertSerialNumbersForDeletedOutboundAsync(entity.Id);
2532   - await RollbackSpCostOnDelete(entity);
  2896 + var isRejected = string.Equals(entity.Djzt, "审核不通过", StringComparison.Ordinal);
  2897 +
  2898 + if (!isRejected)
  2899 + {
  2900 + if (entity.Djlx == "销售退货单" || entity.Djlx == "预售退货单")
  2901 + await TryReverseReturnMemberRefundAsync(entity, "删除单据");
  2902 +
  2903 + await TryReverseSalesOutboundMemberAndCommissionAsync(entity, "删除单据");
  2904 +
  2905 + if (IsStockOutboundDocumentForSerialRevert(entity.Djlx))
  2906 + await RevertSerialNumbersForDeletedOutboundAsync(entity.Id);
  2907 +
  2908 + await RevertSerialNumbersForDeletedReturnAsync(entity);
  2909 + await RollbackSpCostOnDelete(entity);
  2910 + }
  2911 +
  2912 + await DeleteWtXlhTrackingForDocumentAsync(entity.Id);
2533 2913 }
2534 2914  
2535 2915 await _wtDjzyService.DeleteByXsckdAsync(ids);
... ... @@ -2610,6 +2990,37 @@ namespace NCC.Extend.WtXsckd
2610 2990 {
2611 2991 await RollbackSamePriceTransferStock(oldHeader, oldMxList);
2612 2992 }
  2993 +
  2994 + // 编辑前先按旧明细冲回 wt_sp_cost,避免 UpdateSpCostOnCreate 二次扣减/加回
  2995 + var oldLx = oldHeader.Djlx ?? "";
  2996 + var oldDjzt = oldHeader.Djzt ?? "";
  2997 + var skipCostRollback = string.Equals(oldDjzt, "草稿", StringComparison.Ordinal)
  2998 + || string.Equals(oldDjzt, "审核不通过", StringComparison.Ordinal);
  2999 +
  3000 + // 销售类出库:非序列号品会被 DeductWtSpCostNonSerialOutboundAsync 重复扣减
  3001 + if ((oldLx == "销售出库单" || oldLx == "零售单" || oldLx == "预售出库单" || oldLx == "委托代销发货单")
  3002 + && !skipCostRollback && oldMxList.Count > 0)
  3003 + {
  3004 + await RollbackSpCostOnDelete(oldHeader);
  3005 + }
  3006 +
  3007 + // 退货单编辑:先冲回旧明细已加回的 wt_sp_cost
  3008 + if ((string.Equals(oldLx, "销售退货单", StringComparison.Ordinal)
  3009 + || string.Equals(oldLx, "预售退货单", StringComparison.Ordinal)
  3010 + || oldLx.Contains("委托代销退货单"))
  3011 + && !skipCostRollback && oldMxList.Count > 0)
  3012 + {
  3013 + await RollbackSpCostOnDelete(oldHeader);
  3014 + // 退货单编辑:冲回旧单创建时的会员余额/积分退回,后续 TryApplyReturnMemberRefundAsync 按新明细重写
  3015 + if (oldLx == "销售退货单" || oldLx == "预售退货单")
  3016 + await TryReverseReturnMemberRefundAsync(oldHeader, "编辑退货单");
  3017 + }
  3018 +
  3019 + // 采购退货单编辑:先冲回旧明细的成本扣减
  3020 + if (oldLx == "采购退货单" && !skipCostRollback && oldMxList.Count > 0)
  3021 + {
  3022 + await RollbackSpCostOnDelete(oldHeader);
  3023 + }
2613 3024  
2614 3025 //更新销售出库单记录
2615 3026 await _db.Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
... ... @@ -2661,6 +3072,17 @@ namespace NCC.Extend.WtXsckd
2661 3072  
2662 3073 //关闭事务
2663 3074 _db.CommitTran();
  3075 +
  3076 + // 退货单编辑完成后:按新的退货明细重新入账会员余额/积分退回(事务外,与 Create 一致)
  3077 + if ((entity.Djlx == "销售退货单" || entity.Djlx == "预售退货单")
  3078 + && !input.isDraft
  3079 + && !string.Equals(entity.Djzt, "草稿", StringComparison.Ordinal)
  3080 + && !string.Equals(entity.Djzt, "审核不通过", StringComparison.Ordinal))
  3081 + {
  3082 + var updatedEntity = await _db.Queryable<WtXsckdEntity>().FirstAsync(p => p.Id == id);
  3083 + if (updatedEntity != null)
  3084 + await TryApplyReturnMemberRefundAsync(updatedEntity);
  3085 + }
2664 3086 }
2665 3087 catch (Exception)
2666 3088 {
... ... @@ -2689,17 +3111,35 @@ namespace NCC.Extend.WtXsckd
2689 3111 {
2690 3112 _db.BeginTran();
2691 3113  
2692   - // 退货单创建时已入账会员余额/积分;删除时先冲回(审核不通过时已冲过,避免重复)
2693   - if ((entity.Djlx == "销售退货单" || entity.Djlx == "预售退货单")
2694   - && !string.Equals(entity.Djzt, "审核不通过", StringComparison.Ordinal))
2695   - await TryReverseReturnMemberRefundAsync(entity, "删除单据");
  3114 + // 审核不通过的单据在 RejectDocument 中已冲回所有副作用,此处仅清理记录即可
  3115 + var isRejected = string.Equals(entity.Djzt, "审核不通过", StringComparison.Ordinal);
2696 3116  
2697   - // 销售类出库:先恢复本单序列号为在库,再回退成本(与建单时先扣序列号再扣账对称,避免删单后账面与序列号不一致)
2698   - if (IsStockOutboundDocumentForSerialRevert(entity.Djlx))
2699   - await RevertSerialNumbersForDeletedOutboundAsync(entity.Id);
  3117 + if (!isRejected)
  3118 + {
  3119 + // 退货单会员余额/积分冲回
  3120 + if (entity.Djlx == "销售退货单" || entity.Djlx == "预售退货单")
  3121 + await TryReverseReturnMemberRefundAsync(entity, "删除单据");
2700 3122  
2701   - // 删除前回退成本
2702   - await RollbackSpCostOnDelete(entity);
  3123 + // 销售类出库:冲回会员积分/余额 + 删除导购提成
  3124 + await TryReverseSalesOutboundMemberAndCommissionAsync(entity, "删除单据");
  3125 +
  3126 + // 销售类出库:恢复序列号为在库
  3127 + if (IsStockOutboundDocumentForSerialRevert(entity.Djlx))
  3128 + await RevertSerialNumbersForDeletedOutboundAsync(entity.Id);
  3129 +
  3130 + // 退货单:将退货恢复的序列号还原为已售出(须在 DeleteWtXlhTracking 前调用)
  3131 + await RevertSerialNumbersForDeletedReturnAsync(entity);
  3132 +
  3133 + await DeleteWtXlhTrackingForDocumentAsync(entity.Id);
  3134 +
  3135 + // 回退成本
  3136 + await RollbackSpCostOnDelete(entity);
  3137 + }
  3138 + else
  3139 + {
  3140 + // 审核不通过:仅清理残留跟踪(序列号/xlh 回退在 Reject 中已执行,再调是安全 no-op)
  3141 + await DeleteWtXlhTrackingForDocumentAsync(entity.Id);
  3142 + }
2703 3143  
2704 3144 await _wtDjzyService.DeleteByXsckdAsync(id);
2705 3145  
... ... @@ -3258,14 +3698,8 @@ ORDER BY IFNULL(MAX(pp.F_Ppmc), &#39;&#39;), IFNULL(MAX(s.F_Spbm), &#39;&#39;)&quot;;
3258 3698 var pid = productId.Trim();
3259 3699 var wid = warehouseId.Trim();
3260 3700  
3261   - var warehouseIds = await _db.Queryable<WtCkEntity>()
3262   - .Where(c => c.Ssmd == wid || c.Id == wid)
3263   - .Select(c => c.Id)
3264   - .ToListAsync();
3265   - if (warehouseIds == null || warehouseIds.Count == 0)
3266   - {
3267   - warehouseIds = new List<string> { wid };
3268   - }
  3701 + var warehouseIds = await ResolveWarehouseIdsForSpCostFromStoreOrCkAsync(wid);
  3702 + if (warehouseIds.Count == 0) warehouseIds = new List<string> { wid };
3269 3703  
3270 3704 var whSet = new HashSet<string>(
3271 3705 warehouseIds.Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim()),
... ... @@ -3307,6 +3741,7 @@ ORDER BY IFNULL(MAX(pp.F_Ppmc), &#39;&#39;), IFNULL(MAX(s.F_Spbm), &#39;&#39;)&quot;;
3307 3741 return new { success = false, restored = 0, msg = "无明细" };
3308 3742  
3309 3743 var restored = await ApplySalesReturnSerialRestoreForEntityAsync(entity, mxList, id);
  3744 + await EnsureWtXlhAfterSalesReturnCreateAsync(entity, null, mxList, id);
3310 3745 return new { success = true, restored, msg = restored > 0 ? $"已回库 {restored} 条序列号" : "无待回库序列号(可能已处理或原单不匹配)" };
3311 3746 }
3312 3747  
... ... @@ -3325,14 +3760,8 @@ ORDER BY IFNULL(MAX(pp.F_Ppmc), &#39;&#39;), IFNULL(MAX(s.F_Spbm), &#39;&#39;)&quot;;
3325 3760  
3326 3761 try
3327 3762 {
3328   - var warehouseIds = await _db.Queryable<WtCkEntity>()
3329   - .Where(c => c.Ssmd == ckOrMdId || c.Id == ckOrMdId)
3330   - .Select(c => c.Id)
3331   - .ToListAsync();
3332   - if (warehouseIds == null || warehouseIds.Count == 0)
3333   - {
3334   - warehouseIds = new List<string> { ckOrMdId.Trim() };
3335   - }
  3763 + var warehouseIds = await ResolveWarehouseIdsForSpCostFromStoreOrCkAsync(ckOrMdId);
  3764 + if (warehouseIds.Count == 0) warehouseIds = new List<string> { ckOrMdId.Trim() };
3336 3765  
3337 3766 var ps = new List<SugarParameter> { new SugarParameter("@spbh", spbh.Trim()) };
3338 3767 for (var i = 0; i < warehouseIds.Count; i++)
... ... @@ -3357,13 +3786,25 @@ ORDER BY IFNULL(MAX(pp.F_Ppmc), &#39;&#39;), IFNULL(MAX(s.F_Spbm), &#39;&#39;)&quot;;
3357 3786 }
3358 3787 }
3359 3788  
  3789 + private const string PurchaseSummaryJoinFromSql = @"
  3790 +FROM wt_xsckd_mx mx
  3791 +INNER JOIN wt_xsckd d ON d.F_Id = mx.djbh
  3792 +LEFT JOIN wt_sp sp ON sp.F_Id = mx.spbh
  3793 +LEFT JOIN wt_pl pl ON pl.F_Id = sp.F_Pl
  3794 +LEFT JOIN wt_pp pp ON pp.F_Id = sp.F_Pp
  3795 +LEFT JOIN wt_wldw w ON w.F_Id = d.gys
  3796 +LEFT JOIN BASE_USER u ON u.F_Id = d.jsr
  3797 +LEFT JOIN wt_ck ck ON ck.F_Id = IFNULL(NULLIF(TRIM(mx.rkck), ''), d.rkck)
  3798 +WHERE 1 = 1";
  3799 +
3360 3800 /// <summary>
3361   - /// 商品采购订单汇总:按明细行返回过往采购记录(筛选后分页),列与业务导出表一致
  3801 + /// 采购汇总公共 WHERE(需配合含 sp/pl/pp 的 PurchaseSummaryJoinFromSql 使用)
3362 3802 /// </summary>
3363   - /// <param name="input">筛选条件:时间范围、往来单位、经手人、商品、入库仓库、单据类型、分页</param>
3364   - /// <returns>list:明细行;total:总条数</returns>
3365   - [HttpGet("Actions/GetPurchaseSummary")]
3366   - public async Task<dynamic> GetPurchaseSummary([FromQuery] WtPurchaseSummaryQueryInput input = null)
  3803 + private (string whereSql, List<SugarParameter> paramList) BuildPurchaseSummaryWhere(
  3804 + WtPurchaseSummaryQueryInput input,
  3805 + string scopeCategoryId,
  3806 + string scopeBrandId,
  3807 + string scopeProductSpId)
3367 3808 {
3368 3809 input ??= new WtPurchaseSummaryQueryInput();
3369 3810 var whereList = new List<string>();
... ... @@ -3405,34 +3846,22 @@ ORDER BY IFNULL(MAX(pp.F_Ppmc), &#39;&#39;), IFNULL(MAX(s.F_Spbm), &#39;&#39;)&quot;;
3405 3846  
3406 3847 if (DateTime.TryParse(input.StartDate, out var startDate))
3407 3848 {
3408   - whereList.Add("d.djrq >= @startDate");
3409   - paramList.Add(new SugarParameter("@startDate", startDate.Date));
  3849 + whereList.Add("d.djrq >= @purSumStartDate");
  3850 + paramList.Add(new SugarParameter("@purSumStartDate", startDate.Date));
3410 3851 }
3411 3852  
3412 3853 if (DateTime.TryParse(input.EndDate, out var endDate))
3413 3854 {
3414   - whereList.Add("d.djrq < @endDate");
3415   - paramList.Add(new SugarParameter("@endDate", endDate.Date.AddDays(1)));
  3855 + whereList.Add("d.djrq < @purSumEndDate");
  3856 + paramList.Add(new SugarParameter("@purSumEndDate", endDate.Date.AddDays(1)));
3416 3857 }
3417 3858  
3418   - AddInCondition("d.gys", input.ContactUnit, "contactUnit");
3419   -
3420   - // 经手人:主表存用户 ID,筛选按姓名匹配 BASE_USER
3421   - var agentNames = SplitCsv(input.Agent);
3422   - if (agentNames.Count > 0)
3423   - {
3424   - var agentParamNames = new List<string>();
3425   - for (var i = 0; i < agentNames.Count; i++)
3426   - {
3427   - var p = $"@agentName{i}";
3428   - agentParamNames.Add(p);
3429   - paramList.Add(new SugarParameter(p, agentNames[i]));
3430   - }
  3859 + AddInCondition("d.gys", input.ContactUnit, "purSumContact");
3431 3860  
3432   - whereList.Add($"d.jsr IN (SELECT F_Id FROM BASE_USER WHERE F_RealName IN ({string.Join(",", agentParamNames)}))");
3433   - }
  3861 + // 经手人:主表 wt_xsckd.jsr 存 BASE_USER.F_Id,按用户主键 IN 筛选(与前端下拉 value 一致)
  3862 + AddInCondition("d.jsr", input.Agent, "purSumJsr");
3434 3863  
3435   - AddInCondition("IFNULL(NULLIF(TRIM(mx.rkck), ''), d.rkck)", input.Warehouse, "warehouse");
  3864 + AddInCondition("IFNULL(NULLIF(TRIM(mx.rkck), ''), d.rkck)", input.Warehouse, "purSumWh");
3436 3865  
3437 3866 var billTypeValues = SplitCsv(input.BillType);
3438 3867 if (billTypeValues.Count == 0)
... ... @@ -3441,7 +3870,7 @@ ORDER BY IFNULL(MAX(pp.F_Ppmc), &#39;&#39;), IFNULL(MAX(s.F_Spbm), &#39;&#39;)&quot;;
3441 3870 billTypeValues.Add("采购退货单");
3442 3871 }
3443 3872  
3444   - AddInCondition("d.djlx", string.Join(",", billTypeValues), "billType");
  3873 + AddInCondition("d.djlx", string.Join(",", billTypeValues), "purSumDjlx");
3445 3874  
3446 3875 var productValues = SplitCsv(input.Product);
3447 3876 if (productValues.Count > 0)
... ... @@ -3449,17 +3878,182 @@ ORDER BY IFNULL(MAX(pp.F_Ppmc), &#39;&#39;), IFNULL(MAX(s.F_Spbm), &#39;&#39;)&quot;;
3449 3878 var productConditions = new List<string>();
3450 3879 for (var i = 0; i < productValues.Count; i++)
3451 3880 {
3452   - var codeParam = $"@productCode{i}";
3453   - var nameParam = $"@productName{i}";
3454   - productConditions.Add($"(mx.spbh = {codeParam} OR mx.spmc LIKE {nameParam})");
3455   - paramList.Add(new SugarParameter(codeParam, productValues[i]));
3456   - paramList.Add(new SugarParameter(nameParam, $"%{productValues[i]}%"));
  3881 + var pEq = $"@purProdEq{i}";
  3882 + var pLike = $"@purProdLike{i}";
  3883 + productConditions.Add($"(mx.spbh = {pEq} OR sp.F_Spbm = {pEq} OR mx.spmc LIKE {pLike} OR IFNULL(sp.F_Spmc, '') LIKE {pLike})");
  3884 + paramList.Add(new SugarParameter(pEq, productValues[i]));
  3885 + paramList.Add(new SugarParameter(pLike, $"%{productValues[i]}%"));
3457 3886 }
3458 3887  
3459 3888 whereList.Add($"({string.Join(" OR ", productConditions)})");
3460 3889 }
3461 3890  
  3891 + var cat = !string.IsNullOrWhiteSpace(scopeCategoryId) ? scopeCategoryId.Trim() : (input.CategoryId ?? string.Empty).Trim();
  3892 + if (cat == "__NONE__")
  3893 + {
  3894 + whereList.Add("(sp.F_Pl IS NULL OR TRIM(IFNULL(sp.F_Pl,'')) = '')");
  3895 + }
  3896 + else if (!string.IsNullOrEmpty(cat))
  3897 + {
  3898 + whereList.Add("sp.F_Pl = @purSumScopeCat");
  3899 + paramList.Add(new SugarParameter("@purSumScopeCat", cat));
  3900 + }
  3901 +
  3902 + var brand = !string.IsNullOrWhiteSpace(scopeBrandId) ? scopeBrandId.Trim() : (input.BrandId ?? string.Empty).Trim();
  3903 + if (!string.IsNullOrEmpty(brand))
  3904 + {
  3905 + whereList.Add("sp.F_Pp = @purSumScopePp");
  3906 + paramList.Add(new SugarParameter("@purSumScopePp", brand));
  3907 + }
  3908 +
  3909 + var spId = !string.IsNullOrWhiteSpace(scopeProductSpId) ? scopeProductSpId.Trim() : (input.ProductSpId ?? string.Empty).Trim();
  3910 + if (!string.IsNullOrEmpty(spId))
  3911 + {
  3912 + whereList.Add("mx.spbh = @purSumScopeSp");
  3913 + paramList.Add(new SugarParameter("@purSumScopeSp", spId));
  3914 + }
  3915 +
3462 3916 var whereSql = whereList.Count > 0 ? $" AND {string.Join(" AND ", whereList)}" : string.Empty;
  3917 + return (whereSql, paramList);
  3918 + }
  3919 +
  3920 + /// <summary>
  3921 + /// 商品采购汇总(按分类聚合):数量、加权平均入库单价、采购金额。
  3922 + /// </summary>
  3923 + [HttpGet("Actions/GetPurchaseSummaryByCategory")]
  3924 + public async Task<dynamic> GetPurchaseSummaryByCategory([FromQuery] WtPurchaseSummaryQueryInput input = null)
  3925 + {
  3926 + input ??= new WtPurchaseSummaryQueryInput();
  3927 + var (whereSql, paramList) = BuildPurchaseSummaryWhere(input, null, null, null);
  3928 + var sql = $@"
  3929 +SELECT
  3930 + IFNULL(NULLIF(TRIM(sp.F_Pl), ''), '__NONE__') AS `分类Id`,
  3931 + IFNULL(NULLIF(TRIM(MAX(pl.F_Plmc)), ''), '无') AS `分类名称`,
  3932 + '无' AS `商品编号`,
  3933 + IFNULL(NULLIF(TRIM(MAX(pl.F_Plmc)), ''), '无') AS `商品名称`,
  3934 + SUM(CAST(mx.sl AS DECIMAL(18,4))) AS `数量`,
  3935 + CASE WHEN ABS(SUM(CAST(mx.sl AS DECIMAL(18,4)))) < 0.00000001 THEN 0
  3936 + ELSE SUM(CAST(mx.je AS DECIMAL(18,4))) / SUM(CAST(mx.sl AS DECIMAL(18,4))) END AS `入库单价`,
  3937 + SUM(CAST(mx.je AS DECIMAL(18,4))) AS `采购金额`
  3938 +{PurchaseSummaryJoinFromSql}
  3939 +{whereSql}
  3940 +GROUP BY sp.F_Pl, pl.F_Plmc
  3941 +ORDER BY SUM(CAST(mx.je AS DECIMAL(18,4))) DESC";
  3942 + var list = await _db.Ado.GetDataTableAsync(sql, paramList);
  3943 + return list;
  3944 + }
  3945 +
  3946 + /// <summary>
  3947 + /// 商品采购汇总(指定分类下按品牌聚合)。
  3948 + /// </summary>
  3949 + [HttpGet("Actions/GetPurchaseSummaryByBrand")]
  3950 + public async Task<dynamic> GetPurchaseSummaryByBrand([FromQuery] string categoryId, [FromQuery] WtPurchaseSummaryQueryInput input = null)
  3951 + {
  3952 + if (string.IsNullOrWhiteSpace(categoryId))
  3953 + {
  3954 + throw NCCException.Oh("categoryId 不能为空");
  3955 + }
  3956 +
  3957 + input ??= new WtPurchaseSummaryQueryInput();
  3958 + var (whereSql, paramList) = BuildPurchaseSummaryWhere(input, categoryId, null, null);
  3959 + var sql = $@"
  3960 +SELECT
  3961 + IFNULL(NULLIF(TRIM(sp.F_Pp), ''), '') AS `品牌Id`,
  3962 + IFNULL(NULLIF(TRIM(MAX(pp.F_Ppmc)), ''), '无') AS `品牌名称`,
  3963 + '无' AS `商品编号`,
  3964 + IFNULL(NULLIF(TRIM(MAX(pp.F_Ppmc)), ''), '无') AS `商品名称`,
  3965 + SUM(CAST(mx.sl AS DECIMAL(18,4))) AS `数量`,
  3966 + CASE WHEN ABS(SUM(CAST(mx.sl AS DECIMAL(18,4)))) < 0.00000001 THEN 0
  3967 + ELSE SUM(CAST(mx.je AS DECIMAL(18,4))) / SUM(CAST(mx.sl AS DECIMAL(18,4))) END AS `入库单价`,
  3968 + SUM(CAST(mx.je AS DECIMAL(18,4))) AS `采购金额`
  3969 +{PurchaseSummaryJoinFromSql}
  3970 +{whereSql}
  3971 +GROUP BY sp.F_Pp, pp.F_Ppmc
  3972 +ORDER BY SUM(CAST(mx.je AS DECIMAL(18,4))) DESC";
  3973 + var list = await _db.Ado.GetDataTableAsync(sql, paramList);
  3974 + return list;
  3975 + }
  3976 +
  3977 + /// <summary>
  3978 + /// 商品采购汇总(指定分类+品牌下按商品聚合)。
  3979 + /// </summary>
  3980 + [HttpGet("Actions/GetPurchaseSummaryByProductAgg")]
  3981 + public async Task<dynamic> GetPurchaseSummaryByProductAgg([FromQuery] string categoryId, [FromQuery] string brandId, [FromQuery] WtPurchaseSummaryQueryInput input = null)
  3982 + {
  3983 + if (string.IsNullOrWhiteSpace(categoryId))
  3984 + {
  3985 + throw NCCException.Oh("categoryId 不能为空");
  3986 + }
  3987 +
  3988 + if (string.IsNullOrWhiteSpace(brandId))
  3989 + {
  3990 + throw NCCException.Oh("brandId 不能为空");
  3991 + }
  3992 +
  3993 + input ??= new WtPurchaseSummaryQueryInput();
  3994 + var (whereSql, paramList) = BuildPurchaseSummaryWhere(input, categoryId, brandId, null);
  3995 + var sql = $@"
  3996 +SELECT
  3997 + sp.F_Id AS `商品Id`,
  3998 + IFNULL(NULLIF(TRIM(MAX(sp.F_Spbm)), ''), '无') AS `商品编号`,
  3999 + IFNULL(NULLIF(TRIM(MAX(sp.F_Spmc)), ''), '无') AS `商品名称`,
  4000 + IFNULL(NULLIF(TRIM(CONCAT_WS(' / ', NULLIF(TRIM(sp.F_Splx1), ''), NULLIF(TRIM(sp.F_Splx2), ''))), ''), '无') AS `明细分类`,
  4001 + SUM(CAST(mx.sl AS DECIMAL(18,4))) AS `数量`,
  4002 + CASE WHEN ABS(SUM(CAST(mx.sl AS DECIMAL(18,4)))) < 0.00000001 THEN 0
  4003 + ELSE SUM(CAST(mx.je AS DECIMAL(18,4))) / SUM(CAST(mx.sl AS DECIMAL(18,4))) END AS `入库单价`,
  4004 + SUM(CAST(mx.je AS DECIMAL(18,4))) AS `采购金额`
  4005 +{PurchaseSummaryJoinFromSql}
  4006 +{whereSql}
  4007 +GROUP BY sp.F_Id, sp.F_Splx1, sp.F_Splx2
  4008 +ORDER BY IFNULL(MAX(sp.F_Spbm), ''), IFNULL(MAX(sp.F_Spmc), '')";
  4009 + var list = await _db.Ado.GetDataTableAsync(sql, paramList);
  4010 + return list;
  4011 + }
  4012 +
  4013 + /// <summary>
  4014 + /// 商品采购「线性列表」:指定分类下全部采购明细行(最多 2000 条),与明细列表列一致。
  4015 + /// </summary>
  4016 + [HttpGet("Actions/GetPurchaseSummaryLinear")]
  4017 + public async Task<dynamic> GetPurchaseSummaryLinear([FromQuery] string categoryId, [FromQuery] WtPurchaseSummaryQueryInput input = null)
  4018 + {
  4019 + if (string.IsNullOrWhiteSpace(categoryId))
  4020 + {
  4021 + throw NCCException.Oh("categoryId 不能为空");
  4022 + }
  4023 +
  4024 + input ??= new WtPurchaseSummaryQueryInput();
  4025 + var (whereSql, paramList) = BuildPurchaseSummaryWhere(input, categoryId, null, null);
  4026 + const int maxRows = 2000;
  4027 + var sql = $@"
  4028 +SELECT
  4029 + DATE_FORMAT(d.djrq, '%Y-%m-%d') AS `单据日期`,
  4030 + d.F_Id AS `单据编号`,
  4031 + d.djlx AS `单据类型`,
  4032 + IFNULL(NULLIF(TRIM(w.dwmc), ''), '无') AS `往来单位`,
  4033 + IFNULL(NULLIF(TRIM(u.F_RealName), ''), IFNULL(NULLIF(TRIM(d.jsr), ''), '无')) AS `经手人`,
  4034 + IFNULL(NULLIF(TRIM(ck.F_mdmc), ''), '无') AS `仓库名称`,
  4035 + IFNULL(NULLIF(TRIM(mx.spmc), ''), '无') AS `商品名称`,
  4036 + CAST(mx.sl AS DECIMAL(18,4)) AS `数量`,
  4037 + mx.dj AS `入库单价`,
  4038 + mx.je AS `采购金额`
  4039 +{PurchaseSummaryJoinFromSql}
  4040 +{whereSql}
  4041 +ORDER BY d.djrq DESC, d.F_Id, mx.F_Id
  4042 +LIMIT {maxRows}";
  4043 + var list = await _db.Ado.GetDataTableAsync(sql, paramList);
  4044 + return list;
  4045 + }
  4046 +
  4047 + /// <summary>
  4048 + /// 商品采购订单汇总:按明细行返回过往采购记录(筛选后分页),列与业务导出表一致。
  4049 + /// </summary>
  4050 + /// <param name="input">筛选条件:时间范围、往来单位、经手人(用户主键)、商品、入库仓库、单据类型、分页;可选 CategoryId/BrandId/ProductSpId 下钻</param>
  4051 + /// <returns>list:明细行;total:总条数</returns>
  4052 + [HttpGet("Actions/GetPurchaseSummary")]
  4053 + public async Task<dynamic> GetPurchaseSummary([FromQuery] WtPurchaseSummaryQueryInput input = null)
  4054 + {
  4055 + input ??= new WtPurchaseSummaryQueryInput();
  4056 + var (whereSql, paramList) = BuildPurchaseSummaryWhere(input, null, null, null);
3463 4057  
3464 4058 var page = input.CurrentPage.GetValueOrDefault(1);
3465 4059 if (page < 1)
... ... @@ -3480,15 +4074,7 @@ ORDER BY IFNULL(MAX(pp.F_Ppmc), &#39;&#39;), IFNULL(MAX(s.F_Spbm), &#39;&#39;)&quot;;
3480 4074  
3481 4075 var offset = (page - 1) * pageSize;
3482 4076  
3483   - var fromSql = @"
3484   -FROM wt_xsckd_mx mx
3485   -INNER JOIN wt_xsckd d ON d.F_Id = mx.djbh
3486   -LEFT JOIN wt_wldw w ON w.F_Id = d.gys
3487   -LEFT JOIN BASE_USER u ON u.F_Id = d.jsr
3488   -LEFT JOIN wt_ck ck ON ck.F_Id = IFNULL(NULLIF(TRIM(mx.rkck), ''), d.rkck)
3489   -WHERE 1 = 1";
3490   -
3491   - var countSql = "SELECT COUNT(*) " + fromSql + whereSql;
  4077 + var countSql = "SELECT COUNT(*) " + PurchaseSummaryJoinFromSql + whereSql;
3492 4078 var totalObj = await _db.Ado.GetScalarAsync(countSql, paramList);
3493 4079 var total = Convert.ToInt32(totalObj ?? 0);
3494 4080  
... ... @@ -3504,7 +4090,7 @@ SELECT
3504 4090 CAST(mx.sl AS DECIMAL(18,4)) AS `数量`,
3505 4091 mx.dj AS `入库单价`,
3506 4092 mx.je AS `采购金额`
3507   -{fromSql}
  4093 +{PurchaseSummaryJoinFromSql}
3508 4094 {whereSql}
3509 4095 ORDER BY d.djrq DESC, d.F_Id, mx.F_Id
3510 4096 LIMIT {offset}, {pageSize}";
... ... @@ -3875,6 +4461,37 @@ LIMIT {offset}, {pageSize}&quot;;
3875 4461 .ExecuteCommandAsync();
3876 4462 }
3877 4463 }
  4464 +
  4465 + if (!isDraft && serialNumbers != null && serialNumbers.Count > 0 &&
  4466 + !string.IsNullOrEmpty(outDocumentId) &&
  4467 + outDocumentType != "销售退货单" && outDocumentType != "预售退货单" &&
  4468 + outDocumentType != "委托代销退货单" && outDocumentType != "采购退货单")
  4469 + {
  4470 + var spbhList = await _db.Queryable<WtSerialNumberEntity>()
  4471 + .Where(s => serialNumbers.Contains(s.SerialNumber) && s.OutDjbh == outDocumentId)
  4472 + .Select(s => s.Spbh)
  4473 + .ToListAsync();
  4474 + foreach (var sp in spbhList.Distinct(StringComparer.OrdinalIgnoreCase))
  4475 + {
  4476 + if (!string.IsNullOrEmpty(sp))
  4477 + await SyncWtXlhOutboundFromSerialTableAsync(outDocumentId, outDocumentType, sp);
  4478 + }
  4479 + }
  4480 +
  4481 + if (!isDraft && serialNumbers != null && serialNumbers.Count > 0 && !string.IsNullOrEmpty(outDocumentId) &&
  4482 + (outDocumentType == "销售退货单" || outDocumentType == "预售退货单" || outDocumentType == "委托代销退货单"))
  4483 + {
  4484 + var snRows = await _db.Queryable<WtSerialNumberEntity>()
  4485 + .Where(s => serialNumbers.Contains(s.SerialNumber))
  4486 + .Select(s => new { s.SerialNumber, s.Spbh })
  4487 + .ToListAsync();
  4488 + foreach (var g in snRows.GroupBy(x => x.Spbh ?? "", StringComparer.OrdinalIgnoreCase))
  4489 + {
  4490 + if (string.IsNullOrEmpty(g.Key)) continue;
  4491 + await InsertWtXlhDistinctAsync(outDocumentId, outDocumentType, g.Key,
  4492 + g.Select(x => x.SerialNumber).ToList(), "退货入库");
  4493 + }
  4494 + }
3878 4495  
3879 4496 return new { success = true, message = "序列号状态更新成功", created = missingSerialNumbers.Count };
3880 4497 }
... ... @@ -4441,8 +5058,50 @@ LIMIT {offset}, {pageSize}&quot;;
4441 5058 return new { success = false, message = "单据不存在" };
4442 5059 }
4443 5060  
4444   - AppendApprovalSpbzLine(row, "审核不通过", approvalRemark);
  5061 + var rowDjlx = row.Djlx ?? "";
  5062 + var wasNotDraft = !string.Equals(row.Djzt, "草稿", StringComparison.Ordinal);
4445 5063  
  5064 + // ★ 审核不通过 = 单据从未生效:先按旧状态冲回所有 Create 时产生的副作用
  5065 + if (wasNotDraft)
  5066 + {
  5067 + // 销售类出库:冲回 wt_sp_cost / 序列号 / wt_xlh / 会员 / 提成
  5068 + if (rowDjlx == "销售出库单" || rowDjlx == "零售单" || rowDjlx == "预售出库单" || rowDjlx == "委托代销发货单")
  5069 + {
  5070 + if (IsStockOutboundDocumentForSerialRevert(rowDjlx))
  5071 + await RevertSerialNumbersForDeletedOutboundAsync(row.Id);
  5072 + await DeleteWtXlhTrackingForDocumentAsync(row.Id);
  5073 + await RollbackSpCostOnDelete(row);
  5074 + await TryReverseSalesOutboundMemberAndCommissionAsync(row, "审核不通过");
  5075 + }
  5076 + // 退货单:冲回 wt_sp_cost / 序列号还原 / wt_xlh / 会员退回
  5077 + else if (rowDjlx == "销售退货单" || rowDjlx == "预售退货单" || rowDjlx.Contains("委托代销退货单"))
  5078 + {
  5079 + await RevertSerialNumbersForDeletedReturnAsync(row);
  5080 + await DeleteWtXlhTrackingForDocumentAsync(row.Id);
  5081 + await RollbackSpCostOnDelete(row);
  5082 + if (rowDjlx == "销售退货单" || rowDjlx == "预售退货单")
  5083 + await TryReverseReturnMemberRefundAsync(row, "审核不通过");
  5084 + }
  5085 + // 采购退货单:冲回 wt_sp_cost
  5086 + else if (rowDjlx == "采购退货单")
  5087 + {
  5088 + await RollbackSpCostOnDelete(row);
  5089 + }
  5090 + // 变价调拨单:冲回变价成本
  5091 + else if (rowDjlx == "变价调拨单")
  5092 + {
  5093 + var mxList = await _db.Queryable<WtXsckdMxEntity>().Where(d => d.Djbh == id).ToListAsync();
  5094 + if (mxList.Count > 0)
  5095 + {
  5096 + EnsureBjsxColumn();
  5097 + EnsureBjhcbColumn();
  5098 + await RollbackVariablePriceTransferCost(row, mxList);
  5099 + }
  5100 + }
  5101 + }
  5102 +
  5103 + // ★ 更新状态为审核不通过
  5104 + AppendApprovalSpbzLine(row, "审核不通过", approvalRemark);
4446 5105 row.Djzt = "审核不通过";
4447 5106 row.Shr = userId;
4448 5107 row.Shr1 = null;
... ... @@ -4451,10 +5110,6 @@ LIMIT {offset}, {pageSize}&quot;;
4451 5110 .UpdateColumns(x => new { x.Djzt, x.Spbz, x.Shr, x.Shr1, x.Shr2 })
4452 5111 .ExecuteCommandAsync();
4453 5112  
4454   - // 创建退货单时已写入会员余额/积分;审核不通过须冲回,避免反复退审后再退货重复扣减
4455   - if (row.Djlx == "销售退货单" || row.Djlx == "预售退货单")
4456   - await TryReverseReturnMemberRefundAsync(row, "审核不通过");
4457   -
4458 5113 _db.CommitTran();
4459 5114 return new { success = true, message = "已标记为审核不通过" };
4460 5115 }
... ... @@ -4694,6 +5349,100 @@ LIMIT {offset}, {pageSize}&quot;;
4694 5349 }
4695 5350 }
4696 5351  
  5352 + /// <summary>门店名称去后缀简称,与 <c>wt_ck.F_mdmc</c> 前缀匹配(预售转销售库存校验用)。</summary>
  5353 + private static string StoreNameToWarehouseStemForPresaleConvert(string mdmc)
  5354 + {
  5355 + if (string.IsNullOrWhiteSpace(mdmc)) return "";
  5356 + var s = mdmc.Trim();
  5357 + var suffixes = new[]
  5358 + {
  5359 + "旗舰店", "专卖店", "体验店", "直营店", "加盟店", "概念店", "快闪店",
  5360 + "店", "厅", "馆", "部", "行", "中心", "超市", "商场", "广场"
  5361 + };
  5362 + foreach (var suf in suffixes.OrderByDescending(x => x.Length))
  5363 + {
  5364 + if (s.EndsWith(suf, StringComparison.Ordinal) && s.Length > suf.Length)
  5365 + {
  5366 + s = s.Substring(0, s.Length - suf.Length).Trim();
  5367 + break;
  5368 + }
  5369 + }
  5370 +
  5371 + return s;
  5372 + }
  5373 +
  5374 + /// <summary>门店主键对应的 <c>wt_md.F_MdfzId</c>(无则 null)。</summary>
  5375 + private async Task<string> ResolveMdfzIdForPresaleConvertAsync(string storeIdTrimmed)
  5376 + {
  5377 + if (string.IsNullOrEmpty(storeIdTrimmed)) return null;
  5378 + var rows = await _db.Queryable<WtMdEntity>()
  5379 + .Where(m => m.Id == storeIdTrimmed)
  5380 + .Select(m => m.MdfzId)
  5381 + .Take(1)
  5382 + .ToListAsync();
  5383 + return rows.Count > 0 ? rows[0] : null;
  5384 + }
  5385 +
  5386 + private async Task<List<string>> GetWarehouseIdsByStoreNameStemForPresaleConvertAsync(string storeId)
  5387 + {
  5388 + if (string.IsNullOrWhiteSpace(storeId)) return new List<string>();
  5389 + var mdmc = await _db.Queryable<WtMdEntity>()
  5390 + .Where(m => m.Id == storeId)
  5391 + .Select(m => m.Mdmc)
  5392 + .FirstAsync();
  5393 + var stem = StoreNameToWarehouseStemForPresaleConvert(mdmc);
  5394 + if (string.IsNullOrEmpty(stem) || stem.Length < 2) return new List<string>();
  5395 + var ids = await _db.Queryable<WtCkEntity>()
  5396 + .Where(c => c.Mdmc != null && c.Mdmc.StartsWith(stem))
  5397 + .Select(c => c.Id)
  5398 + .ToListAsync();
  5399 + return ids
  5400 + .Where(x => !string.IsNullOrWhiteSpace(x))
  5401 + .Select(x => x.Trim())
  5402 + .Distinct(StringComparer.OrdinalIgnoreCase)
  5403 + .ToList();
  5404 + }
  5405 +
  5406 + /// <summary>
  5407 + /// 预售转销售时按门店/仓库解析 <c>wt_ck</c> 主键列表(含分组 <c>F_ssmd</c>、<c>ck</c> 即仓库主键、名称前缀兜底),与商品列表库存口径一致。
  5408 + /// </summary>
  5409 + private async Task<List<string>> ResolveWarehouseIdsForPresaleConvertAsync(string storeOrWarehouseId)
  5410 + {
  5411 + if (string.IsNullOrWhiteSpace(storeOrWarehouseId)) return new List<string>();
  5412 + var sid = storeOrWarehouseId.Trim();
  5413 + var byCkId = await _db.Queryable<WtCkEntity>().Where(c => c.Id == sid).Select(c => c.Id).Take(1).ToListAsync();
  5414 + if (byCkId.Count > 0) return new List<string> { byCkId[0] };
  5415 +
  5416 + var grp = await ResolveMdfzIdForPresaleConvertAsync(sid);
  5417 + object pars;
  5418 + string whereSql;
  5419 + if (string.IsNullOrEmpty(grp))
  5420 + {
  5421 + whereSql = "(`F_ssmd` = @sid OR FIND_IN_SET(@sid, `F_ssmd`) > 0)";
  5422 + pars = new { sid };
  5423 + }
  5424 + else
  5425 + {
  5426 + whereSql =
  5427 + "( (`F_ssmd` = @sid OR FIND_IN_SET(@sid, `F_ssmd`) > 0) OR " +
  5428 + "(`F_ssmd` = @grp OR FIND_IN_SET(@grp, `F_ssmd`) > 0) )";
  5429 + pars = new { sid, grp };
  5430 + }
  5431 +
  5432 + var ids = await _db.Queryable<WtCkEntity>()
  5433 + .Where(whereSql, pars)
  5434 + .Select(c => c.Id)
  5435 + .ToListAsync();
  5436 + var list = ids
  5437 + .Where(x => !string.IsNullOrWhiteSpace(x))
  5438 + .Select(x => x.Trim())
  5439 + .Distinct(StringComparer.OrdinalIgnoreCase)
  5440 + .ToList();
  5441 + if (list.Count > 0) return list;
  5442 +
  5443 + return await GetWarehouseIdsByStoreNameStemForPresaleConvertAsync(sid);
  5444 + }
  5445 +
4697 5446 /// <summary>
4698 5447 /// 预售出库单转销售出库单
4699 5448 /// </summary>
... ... @@ -4759,54 +5508,38 @@ LIMIT {offset}, {pageSize}&quot;;
4759 5508 return new { success = false, message = "预售出库单明细不存在" };
4760 5509 }
4761 5510  
4762   - // 4. 检查库存是否充足
  5511 + // 4. 检查在库序列号是否充足(与 Create 明细序列号、商品库存口径一致:分组/门店/仓库主键、名称兜底、in_warehouse 误存门店主键)
4763 5512 var insufficientStock = new List<string>();
4764   - var outStoreId = presaleOrder.Cjck; // 出库门店
4765   -
4766   - // 将门店ID转换为仓库ID列表
4767   - var warehouseIds = new List<string>();
4768   - if (!string.IsNullOrEmpty(outStoreId))
4769   - {
4770   - warehouseIds = await _db.Queryable<WtCkEntity>()
4771   - .Where(c => c.Ssmd == outStoreId)
4772   - .Select(c => c.Id)
4773   - .ToListAsync();
4774   - }
4775   -
  5513 + var outStoreId = presaleOrder.Cjck;
  5514 +
4776 5515 foreach (var detail in presaleDetails)
4777 5516 {
4778   - if (!string.IsNullOrEmpty(detail.Spbh) && int.TryParse(detail.Sl, out int requiredQty) && requiredQty > 0)
  5517 + if (string.IsNullOrEmpty(detail.Spbh) || !int.TryParse(detail.Sl, out int requiredQty) || requiredQty <= 0)
  5518 + continue;
  5519 +
  5520 + var detailOutStoreId = !string.IsNullOrEmpty(detail.Ckck) ? detail.Ckck : outStoreId;
  5521 +
  5522 + if (string.IsNullOrEmpty(detailOutStoreId))
4779 5523 {
4780   - // 确定出库门店(优先使用明细的ckck,否则使用主表的cjck)
4781   - var detailOutStoreId = !string.IsNullOrEmpty(detail.Ckck) ? detail.Ckck : outStoreId;
4782   -
4783   - if (string.IsNullOrEmpty(detailOutStoreId))
4784   - {
4785   - insufficientStock.Add($"{detail.Spmc}(未指定出库门店)");
4786   - continue;
4787   - }
4788   -
4789   - // 查询该门店所属仓库中的可用序列号数量
4790   - var detailWarehouseIds = await _db.Queryable<WtCkEntity>()
4791   - .Where(c => c.Ssmd == detailOutStoreId)
4792   - .Select(c => c.Id)
4793   - .ToListAsync();
4794   -
4795   - if (detailWarehouseIds == null || detailWarehouseIds.Count == 0)
4796   - {
4797   - insufficientStock.Add($"{detail.Spmc}(门店未找到关联的仓库)");
4798   - continue;
4799   - }
4800   -
4801   - var availableCount = await _db.Queryable<WtSerialNumberEntity>()
4802   - .Where(s => s.Spbh == detail.Spbh && (s.Status == 0 || s.Status == 3) && detailWarehouseIds.Contains(s.InWarehouse))
4803   - .CountAsync();
4804   -
4805   - if (availableCount < requiredQty)
4806   - {
4807   - insufficientStock.Add($"{detail.Spmc}(需要{requiredQty}个,可用{availableCount}个)");
4808   - }
  5524 + insufficientStock.Add($"{detail.Spmc}(未指定出库门店)");
  5525 + continue;
4809 5526 }
  5527 +
  5528 + var detailWarehouseIds = await ResolveWarehouseIdsForPresaleConvertAsync(detailOutStoreId);
  5529 + if (detailWarehouseIds == null || detailWarehouseIds.Count == 0)
  5530 + detailWarehouseIds = new List<string> { detailOutStoreId };
  5531 +
  5532 + var whSet = new HashSet<string>(
  5533 + detailWarehouseIds.Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim()),
  5534 + StringComparer.OrdinalIgnoreCase);
  5535 +
  5536 + var availableCount = await _db.Queryable<WtSerialNumberEntity>()
  5537 + .Where(s => s.Spbh == detail.Spbh && (s.Status == 0 || s.Status == 3)
  5538 + && (whSet.Contains(s.InWarehouse) || s.InWarehouse == detailOutStoreId))
  5539 + .CountAsync();
  5540 +
  5541 + if (availableCount < requiredQty)
  5542 + insufficientStock.Add($"{detail.Spmc}(需要{requiredQty}个,可用{availableCount}个)");
4810 5543 }
4811 5544  
4812 5545 if (insufficientStock.Any())
... ... @@ -4919,7 +5652,16 @@ LIMIT {offset}, {pageSize}&quot;;
4919 5652 Skmx = presaleOrder.Skmx,
4920 5653 Fkmx = presaleOrder.Fkmx
4921 5654 };
4922   -
  5655 +
  5656 + // 与收银台下单一致:非「后台」来源的销售出库单不走 ERP 待审(见 IsSalesOutboundSkipErpAudit),落库为已审核
  5657 + if (IsSalesOutboundSkipErpAudit(newSalesOrder))
  5658 + {
  5659 + var approver = userId ?? "";
  5660 + newSalesOrder.Djzt = "已审核";
  5661 + newSalesOrder.Shr = approver;
  5662 + newSalesOrder.Shr1 = approver;
  5663 + }
  5664 +
4923 5665 var newSalesOrderEntity = await _db.Insertable(newSalesOrder).ExecuteReturnEntityAsync();
4924 5666  
4925 5667 // 7. 创建销售出库单明细并处理序列号
... ... @@ -4975,6 +5717,7 @@ LIMIT {offset}, {pageSize}&quot;;
4975 5717 .ExecuteCommandAsync();
4976 5718  
4977 5719 totalUpdated += updateCount;
  5720 + await SyncWtXlhOutboundFromSerialTableAsync(newSalesOrderEntity.Id, "销售出库单", newDetail.Spbh);
4978 5721 }
4979 5722 }
4980 5723 }
... ... @@ -5331,7 +6074,7 @@ LIMIT {offset}, {pageSize}&quot;;
5331 6074 {
5332 6075 await _db.Ado.ExecuteCommandAsync(
5333 6076 "INSERT INTO wt_sp_cost (F_Id, spbh, ck, cbj, sl, update_time) VALUES (@id, @spbh, @ck, @cbj, @sl, NOW())",
5334   - new { id = $"{detail.Spbh}_{detailWarehouse}", spbh = detail.Spbh, ck = detailWarehouse, cbj = purchasePrice, sl = qty });
  6077 + new { id = YitIdHelper.NextId().ToString(), spbh = detail.Spbh, ck = detailWarehouse, cbj = purchasePrice, sl = qty });
5335 6078 }
5336 6079 }
5337 6080 }
... ... @@ -5462,7 +6205,6 @@ LIMIT {offset}, {pageSize}&quot;;
5462 6205 {
5463 6206 if (djlx == "销售出库单" || djlx == "零售单" || djlx == "预售出库单" || djlx == "委托代销发货单")
5464 6207 {
5465   - // 草稿不扣减账面库存,避免未生效单据影响 wt_sp_cost
5466 6208 if (isDraft || string.Equals(entity.Djzt, "草稿", StringComparison.Ordinal))
5467 6209 return;
5468 6210  
... ... @@ -5474,16 +6216,9 @@ LIMIT {offset}, {pageSize}&quot;;
5474 6216 if (string.IsNullOrEmpty(detail.Spbh)) continue;
5475 6217 if (!int.TryParse(detail.Sl, out int qty) || qty <= 0) continue;
5476 6218  
5477   - // 兼容前端传门店ID或仓库ID:按明细仓库优先,其次主表出库仓库
5478 6219 var detailStoreOrWarehouseId = !string.IsNullOrEmpty(detail.Ckck) ? detail.Ckck : outStoreId;
5479   - var warehouseIds = await _db.Queryable<WtCkEntity>()
5480   - .Where(c => c.Ssmd == detailStoreOrWarehouseId || c.Id == detailStoreOrWarehouseId)
5481   - .Select(c => c.Id)
5482   - .ToListAsync();
5483   - if (warehouseIds == null || warehouseIds.Count == 0)
5484   - {
5485   - warehouseIds = new List<string> { detailStoreOrWarehouseId };
5486   - }
  6220 + var warehouseIds = await ResolveWarehouseIdsForSpCostFromStoreOrCkAsync(detailStoreOrWarehouseId);
  6221 + if (warehouseIds.Count == 0) continue;
5487 6222  
5488 6223 var costResult = await _db.Ado.SqlQueryAsync<decimal?>(
5489 6224 $"SELECT cbj FROM wt_sp_cost WHERE spbh = @spbh AND ck IN ({string.Join(",", warehouseIds.Select((_, i) => $"@ck{i}"))}) AND cbj > 0 LIMIT 1",
... ... @@ -5511,48 +6246,56 @@ LIMIT {offset}, {pageSize}&quot;;
5511 6246 }
5512 6247 else
5513 6248 {
5514   - // 无序列号/不入序列号管理:不能仅用「在库序列数」同步 sl,否则出库后数量不减少
5515 6249 await DeductWtSpCostNonSerialOutboundAsync(detail.Spbh, warehouseIds, qty);
5516 6250 }
5517 6251 }
5518 6252 }
5519 6253 else if (djlx == "销售退货单" || djlx == "预售退货单" || djlx == "委托代销退货单")
5520 6254 {
5521   - var returnWarehouseId = !string.IsNullOrEmpty(entity.Rkck) ? entity.Rkck : entity.Cjck;
5522   - if (string.IsNullOrEmpty(returnWarehouseId)) return;
5523   -
  6255 + // 与 ApplySalesReturnSerialRestoreForEntityAsync 一致:优先明细入库仓,避免主表 cjck/rkck 与成本行 ck 不一致导致「退货已审但 wt_sp_cost 未加回」
  6256 + if (isDraft || string.Equals(entity.Djzt, "草稿", StringComparison.Ordinal))
  6257 + return;
  6258 +
5524 6259 foreach (var detail in mxList)
5525 6260 {
5526 6261 if (string.IsNullOrEmpty(detail.Spbh)) continue;
5527 6262 if (!int.TryParse(detail.Sl, out int qty) || qty <= 0) continue;
5528   -
5529   - var existing = await _db.Ado.SqlQueryAsync<dynamic>(
5530   - "SELECT sl FROM wt_sp_cost WHERE spbh = @spbh AND ck = @ck LIMIT 1",
5531   - new { spbh = detail.Spbh, ck = returnWarehouseId });
5532   -
5533   - if (existing != null && existing.Count > 0)
  6263 +
  6264 + var rkRaw = !string.IsNullOrEmpty(detail.Rkck) ? detail.Rkck
  6265 + : (!string.IsNullOrEmpty(detail.Ckck) ? detail.Ckck
  6266 + : (!string.IsNullOrEmpty(entity.Rkck) ? entity.Rkck : entity.Cjck));
  6267 + if (string.IsNullOrWhiteSpace(rkRaw)) continue;
  6268 +
  6269 + var warehouseIds = await ResolveWarehouseIdsForSpCostFromStoreOrCkAsync(rkRaw);
  6270 + if (warehouseIds.Count == 0) continue;
  6271 +
  6272 + var strictSerial = await IsProductStrictSerialOutboundAsync(detail.Spbh);
  6273 + if (strictSerial)
5534 6274 {
5535   - await _db.Ado.ExecuteCommandAsync(
5536   - "UPDATE wt_sp_cost SET sl = sl + @qty, update_time = NOW() WHERE spbh = @spbh AND ck = @ck",
5537   - new { qty, spbh = detail.Spbh, ck = returnWarehouseId });
  6275 + foreach (var whId in warehouseIds)
  6276 + {
  6277 + var actualCount = await _db.Ado.GetIntAsync(
  6278 + "SELECT COUNT(*) FROM wt_serial_number WHERE spbh = @spbh AND in_warehouse = @ck AND (status = 0 OR status = 3)",
  6279 + new SugarParameter[] { new SugarParameter("@spbh", detail.Spbh.Trim()), new SugarParameter("@ck", whId) });
  6280 + await _db.Ado.ExecuteCommandAsync(
  6281 + "UPDATE wt_sp_cost SET sl = @sl, update_time = NOW() WHERE spbh = @spbh AND ck = @ck",
  6282 + new { sl = actualCount, spbh = detail.Spbh.Trim(), ck = whId });
  6283 + }
  6284 + }
  6285 + else
  6286 + {
  6287 + await RestoreWtSpCostNonSerialOutboundAsync(detail.Spbh.Trim(), warehouseIds, qty);
5538 6288 }
5539 6289 }
5540 6290 }
5541 6291 else if (djlx == "采购退货单")
5542 6292 {
5543   - // 采购退货:用退货明细中的单价(即原始采购价)做反向加权平均
5544 6293 var outStoreId = entity.Cjck;
5545 6294 if (string.IsNullOrEmpty(outStoreId)) return;
5546   -
5547   - var warehouseIds = await _db.Queryable<WtCkEntity>()
5548   - .Where(c => c.Ssmd == outStoreId || c.Id == outStoreId)
5549   - .Select(c => c.Id)
5550   - .ToListAsync();
5551   - if (warehouseIds == null || warehouseIds.Count == 0)
5552   - {
5553   - warehouseIds = new List<string> { outStoreId };
5554   - }
5555   -
  6295 +
  6296 + var warehouseIds = await ResolveWarehouseIdsForSpCostFromStoreOrCkAsync(outStoreId);
  6297 + if (warehouseIds.Count == 0) return;
  6298 +
5556 6299 foreach (var detail in mxList)
5557 6300 {
5558 6301 if (string.IsNullOrEmpty(detail.Spbh)) continue;
... ... @@ -5719,12 +6462,8 @@ LIMIT {offset}, {pageSize}&quot;;
5719 6462 if (!int.TryParse(detail.Sl, out int qty) || qty <= 0) continue;
5720 6463  
5721 6464 var detailStoreOrWarehouseId = !string.IsNullOrEmpty(detail.Ckck) ? detail.Ckck : outStoreId;
5722   - var warehouseIds = await _db.Queryable<WtCkEntity>()
5723   - .Where(c => c.Ssmd == detailStoreOrWarehouseId || c.Id == detailStoreOrWarehouseId)
5724   - .Select(c => c.Id)
5725   - .ToListAsync();
5726   - if (warehouseIds == null || warehouseIds.Count == 0)
5727   - warehouseIds = new List<string> { detailStoreOrWarehouseId.Trim() };
  6465 + var warehouseIds = await ResolveWarehouseIdsForSpCostFromStoreOrCkAsync(detailStoreOrWarehouseId);
  6466 + if (warehouseIds.Count == 0) continue;
5728 6467  
5729 6468 var strictSerial = await IsProductStrictSerialOutboundAsync(detail.Spbh);
5730 6469 if (strictSerial)
... ... @@ -5747,9 +6486,6 @@ LIMIT {offset}, {pageSize}&quot;;
5747 6486 }
5748 6487 else if (djlx == "销售退货单" || djlx == "预售退货单" || djlx == "委托代销退货单")
5749 6488 {
5750   - var returnWarehouseId = !string.IsNullOrEmpty(entity.Rkck) ? entity.Rkck : entity.Cjck;
5751   - if (string.IsNullOrEmpty(returnWarehouseId)) return;
5752   -
5753 6489 var mxList = await _db.Queryable<WtXsckdMxEntity>()
5754 6490 .Where(d => d.Djbh == id).ToListAsync();
5755 6491  
... ... @@ -5758,23 +6494,40 @@ LIMIT {offset}, {pageSize}&quot;;
5758 6494 if (string.IsNullOrEmpty(detail.Spbh)) continue;
5759 6495 if (!int.TryParse(detail.Sl, out int qty) || qty <= 0) continue;
5760 6496  
5761   - await _db.Ado.ExecuteCommandAsync(
5762   - "UPDATE wt_sp_cost SET sl = sl - @qty, update_time = NOW() WHERE spbh = @spbh AND ck = @ck",
5763   - new { qty, spbh = detail.Spbh, ck = returnWarehouseId });
  6497 + var rkRaw = !string.IsNullOrEmpty(detail.Rkck) ? detail.Rkck
  6498 + : (!string.IsNullOrEmpty(detail.Ckck) ? detail.Ckck
  6499 + : (!string.IsNullOrEmpty(entity.Rkck) ? entity.Rkck : entity.Cjck));
  6500 + if (string.IsNullOrWhiteSpace(rkRaw)) continue;
  6501 +
  6502 + var warehouseIds = await ResolveWarehouseIdsForSpCostFromStoreOrCkAsync(rkRaw);
  6503 + if (warehouseIds.Count == 0) continue;
  6504 +
  6505 + var strictSerial = await IsProductStrictSerialOutboundAsync(detail.Spbh);
  6506 + if (strictSerial)
  6507 + {
  6508 + foreach (var whId in warehouseIds)
  6509 + {
  6510 + var actualCount = await _db.Ado.GetIntAsync(
  6511 + "SELECT COUNT(*) FROM wt_serial_number WHERE spbh = @spbh AND in_warehouse = @ck AND (status = 0 OR status = 3)",
  6512 + new SugarParameter[] { new SugarParameter("@spbh", detail.Spbh.Trim()), new SugarParameter("@ck", whId) });
  6513 + await _db.Ado.ExecuteCommandAsync(
  6514 + "UPDATE wt_sp_cost SET sl = @sl, update_time = NOW() WHERE spbh = @spbh AND ck = @ck",
  6515 + new { sl = actualCount, spbh = detail.Spbh.Trim(), ck = whId });
  6516 + }
  6517 + }
  6518 + else
  6519 + {
  6520 + await DeductWtSpCostNonSerialOutboundAsync(detail.Spbh.Trim(), warehouseIds, qty);
  6521 + }
5764 6522 }
5765 6523 }
5766 6524 else if (djlx == "采购退货单")
5767 6525 {
5768   - // 采购退货单删除:恢复成本(反向操作,相当于再入库)
5769 6526 var outStoreId = entity.Cjck;
5770 6527 if (string.IsNullOrEmpty(outStoreId)) return;
5771   -
5772   - var warehouseIds = await _db.Queryable<WtCkEntity>()
5773   - .Where(c => c.Ssmd == outStoreId || c.Id == outStoreId)
5774   - .Select(c => c.Id)
5775   - .ToListAsync();
5776   - if (warehouseIds == null || warehouseIds.Count == 0)
5777   - warehouseIds = new List<string> { outStoreId };
  6528 +
  6529 + var warehouseIds = await ResolveWarehouseIdsForSpCostFromStoreOrCkAsync(outStoreId);
  6530 + if (warehouseIds.Count == 0) return;
5778 6531  
5779 6532 var mxList = await _db.Queryable<WtXsckdMxEntity>()
5780 6533 .Where(d => d.Djbh == id).ToListAsync();
... ... @@ -5850,18 +6603,13 @@ LIMIT {offset}, {pageSize}&quot;;
5850 6603 }
5851 6604  
5852 6605 /// <summary>
5853   - /// 将门店ID或仓库ID解析为仓库ID列表(与同价/销售成本逻辑一致)
  6606 + /// 将门店ID或仓库ID解析为仓库ID列表(委托至统一解析方法,与商品列表展示口径一致)
5854 6607 /// </summary>
5855 6608 private async Task<List<string>> ResolveWarehouseIdListAsync(string storeOrWarehouseId)
5856 6609 {
5857 6610 if (string.IsNullOrEmpty(storeOrWarehouseId)) return new List<string>();
5858   - var warehouseIds = await _db.Queryable<WtCkEntity>()
5859   - .Where(c => c.Ssmd == storeOrWarehouseId || c.Id == storeOrWarehouseId)
5860   - .Select(c => c.Id)
5861   - .ToListAsync();
5862   - if (warehouseIds == null || warehouseIds.Count == 0)
5863   - warehouseIds = new List<string> { storeOrWarehouseId };
5864   - return warehouseIds;
  6611 + var ids = await ResolveWarehouseIdsForSpCostFromStoreOrCkAsync(storeOrWarehouseId.Trim());
  6612 + return ids.Count > 0 ? ids : new List<string> { storeOrWarehouseId.Trim() };
5865 6613 }
5866 6614  
5867 6615 /// <summary>
... ... @@ -6035,10 +6783,9 @@ LIMIT {offset}, {pageSize}&quot;;
6035 6783 return;
6036 6784 }
6037 6785  
6038   - var rowId = $"{spbh}_{ck}";
6039 6786 await _db.Ado.ExecuteCommandAsync(
6040 6787 "INSERT INTO wt_sp_cost (F_Id, spbh, ck, cbj, sl, update_time) VALUES (@id, @spbh, @ck, @cbj, @sl, NOW())",
6041   - new { id = rowId, spbh, ck, cbj = 0m, sl = qty });
  6788 + new { id = YitIdHelper.NextId().ToString(), spbh, ck, cbj = 0m, sl = qty });
6042 6789 }
6043 6790  
6044 6791 /// <summary>
... ... @@ -6120,10 +6867,9 @@ LIMIT {offset}, {pageSize}&quot;;
6120 6867 }
6121 6868 else
6122 6869 {
6123   - var rowId = $"{spbh}_{ck}";
6124 6870 await _db.Ado.ExecuteCommandAsync(
6125 6871 "INSERT INTO wt_sp_cost (F_Id, spbh, ck, cbj, sl, update_time) VALUES (@id, @spbh, @ck, @cbj, @sl, NOW())",
6126   - new { id = rowId, spbh, ck, cbj = unitPrice, sl = qty });
  6872 + new { id = YitIdHelper.NextId().ToString(), spbh, ck, cbj = unitPrice, sl = qty });
6127 6873 }
6128 6874 }
6129 6875  
... ...
Antis.Erp.Plat/sy/home.html
... ... @@ -1457,7 +1457,20 @@
1457 1457  
1458 1458 const existingItem = this.addgoodlist.find((listItem) => listItem.id === item.id);
1459 1459 if (existingItem) {
  1460 + if (item.mdkc !== undefined && item.mdkc !== null) {
  1461 + existingItem.mdkc = item.mdkc;
  1462 + }
1460 1463 existingItem.quantity += 1;
  1464 + const idx = this.addgoodlist.indexOf(existingItem);
  1465 + if (!(existingItem.isPackageItem && existingItem.packageId)) {
  1466 + if (!existingItem.isPresale && this.parseMdkcNumber(existingItem.mdkc) > 0 &&
  1467 + existingItem.quantity > this.parseMdkcNumber(existingItem.mdkc)) {
  1468 + if (!this.splitLineIfStockInsufficient(existingItem, idx)) {
  1469 + existingItem.quantity -= 1;
  1470 + return;
  1471 + }
  1472 + }
  1473 + }
1461 1474 // 如果之前不是预售,这次又判定为预售,则补上标记
1462 1475 if (isPresale) {
1463 1476 existingItem.isPresale = true;
... ... @@ -2053,6 +2066,41 @@
2053 2066 this.ontype = type;
2054 2067 this.getGoodsList()
2055 2068 },
  2069 + /** 解析商品列表上的门店可售库存(与 WtSp mdkc 一致,向下取整) */
  2070 + parseMdkcNumber(mdkc) {
  2071 + const n = parseFloat(mdkc);
  2072 + if (isNaN(n) || n < 0) return 0;
  2073 + return Math.floor(n);
  2074 + },
  2075 + /**
  2076 + * 同一行 quantity 超过门店库存时拆成两行:现货 + 预售(仅单品,不含套餐子行)。
  2077 + * @returns {boolean} true 已拆分或无需拆分;false 用户取消确认
  2078 + */
  2079 + splitLineIfStockInsufficient(item, index) {
  2080 + if (!item || (item.isPackageItem && item.packageId)) return true;
  2081 + if (item.isPresale) return true;
  2082 + const cap = this.parseMdkcNumber(item.mdkc);
  2083 + const q = parseInt(item.quantity, 10) || 0;
  2084 + if (cap <= 0 || q <= cap) return true;
  2085 + const over = q - cap;
  2086 + if (!window.confirm(
  2087 + `该商品门店现货仅 ${cap} 件,您要了 ${q} 件;多出的 ${over} 件将生成「预售出库单」(到货后再出库)。\n\n是否按此拆分继续?`
  2088 + )) {
  2089 + return false;
  2090 + }
  2091 + item.quantity = cap;
  2092 + if (item.selectedSerialNumbers && item.selectedSerialNumbers.length > cap) {
  2093 + item.selectedSerialNumbers = item.selectedSerialNumbers.slice(0, cap);
  2094 + }
  2095 + const presaleLine = Object.assign({}, item, {
  2096 + quantity: over,
  2097 + isPresale: true,
  2098 + selectedSerialNumbers: []
  2099 + });
  2100 + this.addgoodlist.splice(index + 1, 0, presaleLine);
  2101 + this.showPosToast(`已拆分:现货 ${cap} 件 + 预售 ${over} 件`);
  2102 + return true;
  2103 + },
2056 2104 decreaseQuantity(item, index) {
2057 2105 if (this.addgoodlist[index].quantity > 1) {
2058 2106 this.addgoodlist[index].quantity--;
... ... @@ -2060,6 +2108,14 @@
2060 2108 },
2061 2109 increaseQuantity(item, index) {
2062 2110 this.addgoodlist[index].quantity++;
  2111 + const row = this.addgoodlist[index];
  2112 + if (!row.isPackageItem || !row.packageId) {
  2113 + if (!row.isPresale && this.parseMdkcNumber(row.mdkc) > 0 && row.quantity > this.parseMdkcNumber(row.mdkc)) {
  2114 + if (!this.splitLineIfStockInsufficient(row, index)) {
  2115 + this.addgoodlist[index].quantity--;
  2116 + }
  2117 + }
  2118 + }
2063 2119 },
2064 2120 deleteProduct(index) {
2065 2121 var item = this.addgoodlist[index];
... ...
Antis.Erp.Plat/sy/login.html
... ... @@ -186,13 +186,26 @@
186 186 axios({
187 187 url: that.baseUrl + "/api/Extend/WtMd",
188 188 method: 'GET',
  189 + // 列表接口分页:不传 pageSize 时后端默认 50,门店多于 50 时登录页显示不全
  190 + params: {
  191 + currentPage: 1,
  192 + pageSize: 2000,
  193 + sort: 'asc',
  194 + sidx: 'mdmc'
  195 + },
189 196 headers: {
190 197 'accept': 'text/plain',
191 198 'Content-Type': 'application/json',
192 199 }
193 200 }).then((res) => {
194 201 if (res.data.code === 200) {
195   - that.storeList = res.data.data.list || [];
  202 + var raw = res.data.data.list || [];
  203 + // 门店主键必须当字符串用,避免 JSON 数字精度丢失导致与后台 wt_skzhb.ssmd 对不上
  204 + that.storeList = raw.map(function (s) {
  205 + var o = Object.assign({}, s);
  206 + if (o.id != null && o.id !== '') o.id = String(o.id);
  207 + return o;
  208 + });
196 209 console.log('门店列表加载成功:', that.storeList);
197 210 } else {
198 211 console.error('获取门店列表失败:', res.data);
... ... @@ -284,8 +297,10 @@
284 297 return that.storeIdStr(store.id) === that.storeIdStr(that.selectedStore);
285 298 });
286 299 if (selectedStoreInfo) {
287   - localStorage.setItem('selectedStore', JSON.stringify(selectedStoreInfo));
288   - console.log('门店信息已存储:', selectedStoreInfo);
  300 + var toSave = Object.assign({}, selectedStoreInfo);
  301 + if (toSave.id != null && toSave.id !== '') toSave.id = String(toSave.id);
  302 + localStorage.setItem('selectedStore', JSON.stringify(toSave));
  303 + console.log('门店信息已存储:', toSave);
289 304 }
290 305 // window.alert('登录成功')
291 306 axios({
... ... @@ -299,7 +314,7 @@
299 314 if (res2.data.code === 200) {
300 315 // 使用用户选择的门店ID,而不是用户信息中的默认门店
301 316 // 这样收银员可以选择任意门店进行收银
302   - const storeIdToUse = that.selectedStore || res2.data.data.mdxx;
  317 + const storeIdToUse = String(that.selectedStore || res2.data.data.mdxx || '').trim();
303 318 localStorage.setItem('mdId', storeIdToUse);
304 319 axios({
305 320 url: this.baseUrl + "/api/Extend/WtCk?pageSize=1&ssmd=" + storeIdToUse,
... ...
Antis.Erp.Plat/sy/orders.html
... ... @@ -1056,8 +1056,8 @@
1056 1056 {{order.djlx}}
1057 1057 </div>
1058 1058 </div>
1059   - <div class="order-status" :class="getStatusClass(order.djzt)">
1060   - {{order.djzt || '待审核'}}
  1059 + <div class="order-status" :class="getPresaleListStatusClass(order)">
  1060 + {{ getPresaleListStatusText(order) }}
1061 1061 </div>
1062 1062 </div>
1063 1063  
... ... @@ -1240,7 +1240,7 @@
1240 1240 </div>
1241 1241 <div class="detail-info-item">
1242 1242 <span class="detail-info-label">单据状态:</span>
1243   - <span class="detail-info-value" :style="{color: orderDetail.djzt === '已过账' ? '#52c41a' : (orderDetail.djzt === '草稿' ? '#ff9800' : '#666')}">{{orderDetail.djzt || '待审核'}}</span>
  1243 + <span class="detail-info-value" :style="detailOrderStatusStyle">{{ detailOrderStatusText }}</span>
1244 1244 </div>
1245 1245 <div class="detail-info-item">
1246 1246 <span class="detail-info-label">出库仓库:</span>
... ... @@ -2647,6 +2647,16 @@
2647 2647 if (status === '草稿') return 'status-draft';
2648 2648 return '';
2649 2649 },
  2650 + /** 预售列表:已转销售的单据库内 djzt 可能仍为待审核,与 ERP「无需审核」语义对齐展示 */
  2651 + getPresaleListStatusText(order) {
  2652 + if (!order) return '待审核';
  2653 + if (this.parsePresaleConvertedChdId(order.bz)) return '已转销售';
  2654 + return order.djzt || '待审核';
  2655 + },
  2656 + getPresaleListStatusClass(order) {
  2657 + if (this.parsePresaleConvertedChdId(order && order.bz)) return 'status-completed';
  2658 + return this.getStatusClass(order && order.djzt);
  2659 + },
2650 2660 // ✅ 查看订单详情
2651 2661 async viewDetails(order) {
2652 2662 this.detailModalVisible = true;
... ... @@ -3304,6 +3314,24 @@
3304 3314 if (lx !== '预售出库单' && lx !== '预售单') return '';
3305 3315 return this.parsePresaleConvertedChdId(this.orderDetail.bz);
3306 3316 },
  3317 + /** 详情弹窗「单据状态」:已转销售预售单展示业务态,与列表一致 */
  3318 + detailOrderStatusText() {
  3319 + if (!this.orderDetail) return '待审核';
  3320 + const lx = String(this.orderDetail.djlx || '').trim();
  3321 + if ((lx === '预售出库单' || lx === '预售单') && this.parsePresaleConvertedChdId(this.orderDetail.bz))
  3322 + return '已转销售';
  3323 + return this.orderDetail.djzt || '待审核';
  3324 + },
  3325 + detailOrderStatusStyle() {
  3326 + if (!this.orderDetail) return { color: '#666' };
  3327 + const z = this.orderDetail.djzt;
  3328 + if (z === '已过账') return { color: '#52c41a' };
  3329 + if (z === '草稿') return { color: '#ff9800' };
  3330 + const lx = String(this.orderDetail.djlx || '').trim();
  3331 + if ((lx === '预售出库单' || lx === '预售单') && this.parsePresaleConvertedChdId(this.orderDetail.bz))
  3332 + return { color: '#52c41a' };
  3333 + return { color: '#666' };
  3334 + },
3307 3335 /** 详情底部:当前单可直接发起退货(未转销售的预售/销售出库单) */
3308 3336 detailCanInitiateReturn() {
3309 3337 if (!this.orderDetail || this.loadingDetail) return false;
... ...
Antis.Erp.Plat/sy/settlement.html
... ... @@ -4058,8 +4058,8 @@
4058 4058 :class="{ 'is-selected': String(payment.skzh || '') === String(accountDictId(acc)) }"
4059 4059 @click.stop="selectComboPaymentAccount(index, acc)"
4060 4060 >
4061   - <img :src="getAccountIcon(acc.zhmc)" class="combo-account-chip-icon" alt="" />
4062   - <span>{{ acc.zhmc }}</span>
  4061 + <img :src="getAccountIcon(accountRowCaption(acc))" class="combo-account-chip-icon" alt="" />
  4062 + <span>{{ accountRowCaption(acc) }}</span>
4063 4063 </button>
4064 4064 </div>
4065 4065 </div>
... ... @@ -4646,14 +4646,17 @@
4646 4646 },
4647 4647 /** 左侧摘要:入账账户展示名 */
4648 4648 directReceiptCaption() {
4649   - if (this.lastDirectAccount && this.lastDirectAccount.zhmc) return this.lastDirectAccount.zhmc;
  4649 + if (this.lastDirectAccount) {
  4650 + var c = this.accountRowCaption(this.lastDirectAccount);
  4651 + if (c !== '无') return c;
  4652 + }
4650 4653 if (this.info.skzh === '余额') return '余额';
4651 4654 const sk = this.info.skzh;
4652 4655 if (!sk) return '无';
4653 4656 const acc = (this.accountList || []).find(a =>
4654 4657 String(this.accountDictId(a)) === String(sk) || String(a.id) === String(sk)
4655 4658 );
4656   - if (acc) return acc.zhmc;
  4659 + if (acc) return this.accountRowCaption(acc);
4657 4660 return sk;
4658 4661 }
4659 4662 },
... ... @@ -4759,7 +4762,7 @@
4759 4762 if (!row || !row.skzh) return '无';
4760 4763 var id = String(row.skzh);
4761 4764 var acc = (this.accountList || []).find(a => String(this.accountDictId(a)) === id || String(a.id) === id);
4762   - if (acc) return acc.zhmc;
  4765 + if (acc) return this.accountRowCaption(acc);
4763 4766 return id;
4764 4767 },
4765 4768 /** skmx 预览行:入账账户展示名 */
... ... @@ -4767,7 +4770,7 @@
4767 4770 if (!row || !row.skzh) return '无';
4768 4771 var id = String(row.skzh);
4769 4772 var acc = (this.accountList || []).find(a => String(this.accountDictId(a)) === id || String(a.id) === id);
4770   - if (acc) return acc.zhmc;
  4773 + if (acc) return this.accountRowCaption(acc);
4771 4774 return id;
4772 4775 },
4773 4776 fillLineRemaining(index) {
... ... @@ -4890,7 +4893,9 @@
4890 4893 if (!sk || sk === '组合支付' || sk === '余额') return '';
4891 4894 const s = String(sk).trim();
4892 4895 if (/^\d{10,}$/.test(s)) return s;
4893   - const acc = (this.accountList || []).find(a => a.zhmc === sk);
  4896 + const acc = (this.accountList || []).find(a =>
  4897 + a.zhmc === sk || this.accountRowCaption(a) === sk || String(this.accountDictId(a)) === s
  4898 + );
4894 4899 return acc ? this.accountDictId(acc) : '';
4895 4900 },
4896 4901 /**
... ... @@ -5023,22 +5028,25 @@
5023 5028 });
5024 5029 return cents / 100;
5025 5030 },
5026   - // ✅ 获取当前选择的门店ID(登录时选择的门店
  5031 + // ✅ 获取当前选择的门店ID(登录时选择的门店;统一为字符串,避免大整数精度丢失
5027 5032 getSelectedStoreId() {
5028 5033 try {
5029 5034 const selectedStore = localStorage.getItem('selectedStore');
5030 5035 if (selectedStore) {
5031 5036 const store = JSON.parse(selectedStore);
5032   - return store.id;
  5037 + if (store && store.id != null && String(store.id).trim() !== '') return String(store.id).trim();
  5038 + if (store && store.Id != null && String(store.Id).trim() !== '') return String(store.Id).trim();
5033 5039 }
5034 5040 } catch (e) {
5035 5041 console.warn('无法获取 selectedStore:', e);
5036 5042 }
5037   - // 降级方案:使用导购员的门店
  5043 + var mdId = localStorage.getItem('mdId');
  5044 + if (mdId != null && String(mdId).trim() !== '') return String(mdId).trim();
5038 5045 try {
5039 5046 const ckinfo = localStorage.getItem('ckinfo');
5040 5047 if (ckinfo) {
5041   - return JSON.parse(ckinfo).id;
  5048 + const ck = JSON.parse(ckinfo);
  5049 + if (ck && ck.id != null) return String(ck.id).trim();
5042 5050 }
5043 5051 } catch (e) {
5044 5052 console.warn('无法获取 ckinfo:', e);
... ... @@ -5081,15 +5089,9 @@
5081 5089 // ✅ 加载账户列表(根据门店过滤)
5082 5090 async loadAccountList() {
5083 5091 try {
5084   - // 获取登录时选择的门店ID
5085 5092 const storeId = this.getSelectedStoreId();
5086   -
5087   - // 调用账户核销表API,根据门店过滤
5088   - const params = {};
5089   - if (storeId) {
5090   - params.ssmd = storeId;
5091   - }
5092   -
  5093 + const params = { currentPage: 1, pageSize: 500, sort: 'desc', sidx: 'id' };
  5094 + if (storeId) params.ssmd = storeId;
5093 5095 const response = await axios({
5094 5096 url: this.baseUrl + "/api/Extend/WtSkzhb",
5095 5097 method: 'GET',
... ... @@ -5098,11 +5100,11 @@
5098 5100 Authorization: localStorage.getItem('token')
5099 5101 }
5100 5102 });
5101   -
5102 5103 if (response.data.code === 200) {
5103   - // 从分页结果中获取列表
5104   - this.accountList = response.data.data.list || [];
5105   - console.log('✅ 加载账户列表成功(门店过滤):', this.accountList);
  5104 + var inner = response.data.data;
  5105 + var list = (inner && inner.list) || response.data.list || [];
  5106 + this.accountList = list;
  5107 + console.log('✅ 加载账户列表 门店=' + (storeId || '未传') + ' 条数=' + list.length, list);
5106 5108 } else {
5107 5109 console.error('❌ 加载账户列表失败:', response.data.msg);
5108 5110 this.accountList = [];
... ... @@ -5112,6 +5114,15 @@
5112 5114 this.accountList = [];
5113 5115 }
5114 5116 },
  5117 + /** 入账账户卡片展示名(接口 zhmc 可能为空时兜底) */
  5118 + accountRowCaption(acc) {
  5119 + if (!acc) return '无';
  5120 + var z = acc.zhmc != null ? String(acc.zhmc).trim() : '';
  5121 + if (z) return z;
  5122 + var sid = acc.skzhDictId != null ? String(acc.skzhDictId).trim() : '';
  5123 + if (sid) return '账户 ' + sid;
  5124 + return '无';
  5125 + },
5115 5126  
5116 5127 // ✅ 根据账户名称获取图标路径
5117 5128 getAccountIcon(accountName) {
... ... @@ -5141,17 +5152,18 @@
5141 5152 return 'images/member16.png';
5142 5153 },
5143 5154  
5144   - // ✅ 处理账户点击事件
  5155 + // ✅ 处理账户点击事件(允许接口未解析出 zhmc,只要有 skzhDictId 即可)
5145 5156 selectAccount(account) {
5146   - if (!account || !account.zhmc) {
5147   - return;
5148   - }
  5157 + if (!account) return;
  5158 + var zhid = this.accountDictId(account);
  5159 + if (!zhid) return;
  5160 + var cap = this.accountRowCaption(account);
5149 5161 this.lastDirectAccount = {
5150 5162 id: account.id,
5151   - zhmc: account.zhmc,
  5163 + zhmc: cap !== '无' ? cap : zhid,
5152 5164 skzhDictId: account.skzhDictId
5153 5165 };
5154   - this.info.skzh = account.zhmc;
  5166 + this.info.skzh = cap !== '无' ? cap : zhid;
5155 5167 },
5156 5168  
5157 5169 // 新增方法
... ... @@ -5743,6 +5755,21 @@
5743 5755 return orders;
5744 5756 };
5745 5757  
  5758 + // ✅ 拆单前提示:仅「同一笔收款里既有现货又有预售」时确认(纯预售在收银首页加购时已提示过)
  5759 + if (presaleItems.length > 0 && inStockItems.length > 0) {
  5760 + const presaleNames = presaleItems.map(function (i) { return i.spmc || i.spbm || '商品'; });
  5761 + var uniqNames = [];
  5762 + presaleNames.forEach(function (n) {
  5763 + if (uniqNames.indexOf(n) < 0) uniqNames.push(n);
  5764 + });
  5765 + var nameStr = uniqNames.slice(0, 5).join('、') + (uniqNames.length > 5 ? '…' : '');
  5766 + if (!window.confirm(
  5767 + '部分商品超过门店现货数量,本笔将同时生成「销售出库单」与「预售出库单」。\n\n预售涉及:' + nameStr + '\n\n确认按此拆单并继续收款?'
  5768 + )) {
  5769 + return;
  5770 + }
  5771 + }
  5772 +
5746 5773 // ✅ 执行创建订单
5747 5774 createOrders().then(async (orders) => {
5748 5775 if (orders.length > 0) {
... ... @@ -5822,6 +5849,7 @@
5822 5849 this.activePaymentLineIndex = this.paymentCombinations.length - 1;
5823 5850 this.selectedPaymentMethod = method;
5824 5851 this.selectedPaymentAmount = '';
  5852 + if (method === '入账账户') this.loadAccountList();
5825 5853 },
5826 5854 removePaymentMethod(index) {
5827 5855 this.paymentCombinations.splice(index, 1);
... ...