Showing
18 changed files
with
4618 additions
and
4 deletions
Too many changes to show.
To preserve performance only 18 of 28 files are displayed.
api/procure-manage/salesmanQuotation.js
0 → 100644
| 1 | +import request from '@/utils/request' | ||
| 2 | +import { ContentTypeEnum } from '@/utils/httpEnum' | ||
| 3 | + | ||
| 4 | +export function salesmanQuotationQueryApi(params) { | ||
| 5 | + return request({ | ||
| 6 | + url: '/procurement/salesmanQuotation/query', | ||
| 7 | + method: 'get', | ||
| 8 | + params | ||
| 9 | + }) | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +// 生成编号 | ||
| 13 | +export function salesmanQuotationGenerateCodeApi() { | ||
| 14 | + return request({ | ||
| 15 | + url: '/procurement/salesmanQuotation/generateCode', | ||
| 16 | + method: 'get' | ||
| 17 | + }) | ||
| 18 | +} | ||
| 19 | + | ||
| 20 | +// 新增保存 | ||
| 21 | +export function salesmanQuotationSaveApi(data) { | ||
| 22 | + return request({ | ||
| 23 | + url: '/procurement/salesmanQuotation', | ||
| 24 | + method: 'post', | ||
| 25 | + data, | ||
| 26 | + contentType: ContentTypeEnum.JSON | ||
| 27 | + }) | ||
| 28 | +} | ||
| 29 | + | ||
| 30 | +// 详情 | ||
| 31 | +export function salesmanQuotationDetailApi(params) { | ||
| 32 | + return request({ | ||
| 33 | + url: '/procurement/salesmanQuotation', | ||
| 34 | + method: 'get', | ||
| 35 | + params | ||
| 36 | + }) | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +// 审核详情 | ||
| 40 | +export function salesmanQuotationGetExamineByIdApi(id) { | ||
| 41 | + return request({ | ||
| 42 | + url: '/procurement/salesmanQuotation/getExamineById', | ||
| 43 | + method: 'get', | ||
| 44 | + params: { id } | ||
| 45 | + }) | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +// 编辑 | ||
| 49 | +export function salesmanQuotationUpdateApi(data) { | ||
| 50 | + return request({ | ||
| 51 | + url: '/procurement/salesmanQuotation', | ||
| 52 | + method: 'put', | ||
| 53 | + data, | ||
| 54 | + contentType: ContentTypeEnum.JSON | ||
| 55 | + }) | ||
| 56 | +} | ||
| 57 | + | ||
| 58 | +// 品种关系查询 | ||
| 59 | +export function breedRelationshipQueryApi(params) { | ||
| 60 | + return request({ | ||
| 61 | + url: '/baseData/breedRelationship/query', | ||
| 62 | + method: 'get', | ||
| 63 | + params | ||
| 64 | + }) | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +// 取消 | ||
| 68 | +export function salesmanQuotationCancelApi(params) { | ||
| 69 | + return request({ | ||
| 70 | + url: '/procurement/salesmanQuotation/cancel', | ||
| 71 | + method: 'post', | ||
| 72 | + params | ||
| 73 | + }) | ||
| 74 | +} |
api/procure-manage/salesmanQuotationPeer.js
0 → 100644
| 1 | +import request from '@/utils/request' | ||
| 2 | +import { ContentTypeEnum } from '@/utils/httpEnum' | ||
| 3 | + | ||
| 4 | +export function salesmanQuotationPeerQueryApi(params) { | ||
| 5 | + return request({ | ||
| 6 | + url: '/procurement/salesmanQuotationPeer/query', | ||
| 7 | + method: 'get', | ||
| 8 | + params | ||
| 9 | + }) | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +export function salesmanQuotationPeerSaveApi(data) { | ||
| 13 | + return request({ | ||
| 14 | + url: '/procurement/salesmanQuotationPeer', | ||
| 15 | + method: 'post', | ||
| 16 | + data, | ||
| 17 | + contentType: ContentTypeEnum.JSON | ||
| 18 | + }) | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +export function salesmanQuotationPeerGetApi(id) { | ||
| 22 | + return request({ | ||
| 23 | + url: '/procurement/salesmanQuotationPeer', | ||
| 24 | + method: 'get', | ||
| 25 | + params: { id } | ||
| 26 | + }) | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +export function salesmanQuotationPeerUpdateApi(data) { | ||
| 30 | + return request({ | ||
| 31 | + url: '/procurement/salesmanQuotationPeer', | ||
| 32 | + method: 'put', | ||
| 33 | + data, | ||
| 34 | + contentType: ContentTypeEnum.JSON | ||
| 35 | + }) | ||
| 36 | +} | ||
| 37 | + | ||
| 38 | +export function salesmanQuotationPeerDeleteApi(id) { | ||
| 39 | + return request({ | ||
| 40 | + url: '/procurement/salesmanQuotationPeer', | ||
| 41 | + method: 'delete', | ||
| 42 | + params: { id } | ||
| 43 | + }) | ||
| 44 | +} |
api/procure-manage/supplierQuotationDeal.js
0 → 100644
| 1 | +import request from '@/utils/request' | ||
| 2 | +import { ContentTypeEnum } from '@/utils/httpEnum' | ||
| 3 | + | ||
| 4 | +export function supplierQuotationDealQueryApi(params) { | ||
| 5 | + return request({ | ||
| 6 | + url: '/procurement/supplierQuotationDeal/query', | ||
| 7 | + method: 'get', | ||
| 8 | + params | ||
| 9 | + }) | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +export function supplierQuotationDealGetApi(id) { | ||
| 13 | + return request({ | ||
| 14 | + url: '/procurement/supplierQuotationDeal', | ||
| 15 | + method: 'get', | ||
| 16 | + params: { id } | ||
| 17 | + }) | ||
| 18 | +} | ||
| 19 | + | ||
| 20 | +// 可分配人员 | ||
| 21 | +export function supplierQuotationDealAssignUsersApi(params) { | ||
| 22 | + return request({ | ||
| 23 | + url: '/procurement/supplierQuotationDeal/assignUsers', | ||
| 24 | + method: 'get', | ||
| 25 | + params | ||
| 26 | + }) | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +// 分配 | ||
| 30 | +export function supplierQuotationDealAssignApi(data) { | ||
| 31 | + return request({ | ||
| 32 | + url: '/procurement/supplierQuotationDeal/assign', | ||
| 33 | + method: 'put', | ||
| 34 | + data, | ||
| 35 | + contentType: ContentTypeEnum.JSON | ||
| 36 | + }) | ||
| 37 | +} |
| 1 | +import request from '@/utils/request' | ||
| 2 | +import { ContentTypeEnum } from '@/utils/httpEnum' | ||
| 3 | + | ||
| 4 | +export function supplierQuotationProjectQueryApi(params) { | ||
| 5 | + return request({ | ||
| 6 | + url: '/procurement/supplierQuotationProject/query', | ||
| 7 | + method: 'get', | ||
| 8 | + params | ||
| 9 | + }) | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +// 新增报价项目 | ||
| 13 | +export function supplierQuotationProjectSaveApi(data) { | ||
| 14 | + return request({ | ||
| 15 | + url: '/procurement/supplierQuotationProject', | ||
| 16 | + method: 'post', | ||
| 17 | + data, | ||
| 18 | + contentType: ContentTypeEnum.JSON | ||
| 19 | + }) | ||
| 20 | +} | ||
| 21 | + | ||
| 22 | +// 详情 | ||
| 23 | +export function supplierQuotationProjectDetailApi(params) { | ||
| 24 | + return request({ | ||
| 25 | + url: '/procurement/supplierQuotationProject', | ||
| 26 | + method: 'get', | ||
| 27 | + params | ||
| 28 | + }) | ||
| 29 | +} | ||
| 30 | + | ||
| 31 | +// 修改 | ||
| 32 | +export function supplierQuotationProjectUpdateApi(data) { | ||
| 33 | + return request({ | ||
| 34 | + url: '/procurement/supplierQuotationProject', | ||
| 35 | + method: 'put', | ||
| 36 | + data, | ||
| 37 | + contentType: ContentTypeEnum.JSON | ||
| 38 | + }) | ||
| 39 | +} | ||
| 40 | + | ||
| 41 | +// 报价 | ||
| 42 | +export function supplierQuotationProjectQuoteApi(data) { | ||
| 43 | + return request({ | ||
| 44 | + url: '/procurement/supplierQuotationProjectQuote', | ||
| 45 | + method: 'post', | ||
| 46 | + data, | ||
| 47 | + contentType: ContentTypeEnum.JSON | ||
| 48 | + }) | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +// 发布(更新状态) | ||
| 52 | +export function supplierQuotationProjectUpdateStatusApi(params) { | ||
| 53 | + return request({ | ||
| 54 | + url: '/procurement/supplierQuotationProject/updateStatus', | ||
| 55 | + method: 'get', | ||
| 56 | + params | ||
| 57 | + }) | ||
| 58 | +} |
| @@ -4,8 +4,8 @@ module.exports = { | @@ -4,8 +4,8 @@ module.exports = { | ||
| 4 | themeColor: '#3d48a3', | 4 | themeColor: '#3d48a3', |
| 5 | 5 | ||
| 6 | // baseUrl: 'http://ft.wecando21cn.com/api', | 6 | // baseUrl: 'http://ft.wecando21cn.com/api', |
| 7 | - baseUrl: 'http://gjtd.ahcjxc.com:81/api', | ||
| 8 | - // baseUrl: 'http://erp.qgutech.com/api', | 7 | + // baseUrl: 'http://gjtd.ahcjxc.com:81/api', |
| 8 | + baseUrl: 'http://erp.qgutech.com/api', | ||
| 9 | // baseUrl: 'http://10.9.5.246:8081', | 9 | // baseUrl: 'http://10.9.5.246:8081', |
| 10 | // 应用信息 | 10 | // 应用信息 |
| 11 | appInfo: { | 11 | appInfo: { |
| @@ -276,6 +276,143 @@ | @@ -276,6 +276,143 @@ | ||
| 276 | } | 276 | } |
| 277 | }, | 277 | }, |
| 278 | { | 278 | { |
| 279 | + "path": "pages/sales-price/index", | ||
| 280 | + "style": { | ||
| 281 | + "navigationBarTitleText": "业务员报价单", | ||
| 282 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 283 | + "navigationBarTextStyle": "black" | ||
| 284 | + } | ||
| 285 | + }, | ||
| 286 | + { | ||
| 287 | + "path": "pages/sales-price/add", | ||
| 288 | + "style": { | ||
| 289 | + "navigationBarTitleText": "新增业务员报价单", | ||
| 290 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 291 | + "navigationBarTextStyle": "black" | ||
| 292 | + } | ||
| 293 | + }, | ||
| 294 | + { | ||
| 295 | + "path": "pages/sales-price/modify", | ||
| 296 | + "style": { | ||
| 297 | + "navigationBarTitleText": "编辑业务员报价单", | ||
| 298 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 299 | + "navigationBarTextStyle": "black" | ||
| 300 | + } | ||
| 301 | + }, | ||
| 302 | + { | ||
| 303 | + "path": "pages/sales-price/detail", | ||
| 304 | + "style": { | ||
| 305 | + "navigationBarTitleText": "查看业务员报价单", | ||
| 306 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 307 | + "navigationBarTextStyle": "black" | ||
| 308 | + } | ||
| 309 | + }, | ||
| 310 | + { | ||
| 311 | + "path": "pages/sales-price/copy", | ||
| 312 | + "style": { | ||
| 313 | + "navigationBarTitleText": "复制业务员报价单", | ||
| 314 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 315 | + "navigationBarTextStyle": "black" | ||
| 316 | + } | ||
| 317 | + }, | ||
| 318 | + | ||
| 319 | + { | ||
| 320 | + "path": "pages/supplier-price/index", | ||
| 321 | + "style": { | ||
| 322 | + "navigationBarTitleText": "报价项目", | ||
| 323 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 324 | + "navigationBarTextStyle": "black" | ||
| 325 | + } | ||
| 326 | + }, | ||
| 327 | + { | ||
| 328 | + "path": "pages/supplier-price/add", | ||
| 329 | + "style": { | ||
| 330 | + "navigationBarTitleText": "新增报价项目", | ||
| 331 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 332 | + "navigationBarTextStyle": "black" | ||
| 333 | + } | ||
| 334 | + }, | ||
| 335 | + { | ||
| 336 | + "path": "pages/supplier-price/detail", | ||
| 337 | + "style": { | ||
| 338 | + "navigationBarTitleText": "查看报价项目", | ||
| 339 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 340 | + "navigationBarTextStyle": "black" | ||
| 341 | + } | ||
| 342 | + }, | ||
| 343 | + { | ||
| 344 | + "path": "pages/supplier-price/modify", | ||
| 345 | + "style": { | ||
| 346 | + "navigationBarTitleText": "编辑报价项目", | ||
| 347 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 348 | + "navigationBarTextStyle": "black" | ||
| 349 | + } | ||
| 350 | + }, | ||
| 351 | + { | ||
| 352 | + "path": "pages/supplier-price/quote", | ||
| 353 | + "style": { | ||
| 354 | + "navigationBarTitleText": "报价", | ||
| 355 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 356 | + "navigationBarTextStyle": "black" | ||
| 357 | + } | ||
| 358 | + }, | ||
| 359 | + { | ||
| 360 | + "path": "pages/quote-manage/index", | ||
| 361 | + "style": { | ||
| 362 | + "navigationBarTitleText": "报价管理", | ||
| 363 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 364 | + "navigationBarTextStyle": "black" | ||
| 365 | + } | ||
| 366 | + }, | ||
| 367 | + { | ||
| 368 | + "path": "pages/quote-manage/detail", | ||
| 369 | + "style": { | ||
| 370 | + "navigationBarTitleText": "报价管理详情", | ||
| 371 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 372 | + "navigationBarTextStyle": "black" | ||
| 373 | + } | ||
| 374 | + }, | ||
| 375 | + { | ||
| 376 | + "path": "pages/quote-manage/assign", | ||
| 377 | + "style": { | ||
| 378 | + "navigationBarTitleText": "分配负责人", | ||
| 379 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 380 | + "navigationBarTextStyle": "black" | ||
| 381 | + } | ||
| 382 | + }, | ||
| 383 | + { | ||
| 384 | + "path": "pages/peer-info/index", | ||
| 385 | + "style": { | ||
| 386 | + "navigationBarTitleText": "同行信息", | ||
| 387 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 388 | + "navigationBarTextStyle": "black" | ||
| 389 | + } | ||
| 390 | + }, | ||
| 391 | + { | ||
| 392 | + "path": "pages/peer-info/add", | ||
| 393 | + "style": { | ||
| 394 | + "navigationBarTitleText": "新增同行信息", | ||
| 395 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 396 | + "navigationBarTextStyle": "black" | ||
| 397 | + } | ||
| 398 | + }, | ||
| 399 | + { | ||
| 400 | + "path": "pages/peer-info/modify", | ||
| 401 | + "style": { | ||
| 402 | + "navigationBarTitleText": "编辑同行信息", | ||
| 403 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 404 | + "navigationBarTextStyle": "black" | ||
| 405 | + } | ||
| 406 | + }, | ||
| 407 | + { | ||
| 408 | + "path": "pages/peer-info/detail", | ||
| 409 | + "style": { | ||
| 410 | + "navigationBarTitleText": "查看同行信息", | ||
| 411 | + "navigationBarBackgroundColor": "#ffffff", | ||
| 412 | + "navigationBarTextStyle": "black" | ||
| 413 | + } | ||
| 414 | + }, | ||
| 415 | + { | ||
| 279 | "path": "pages/order_list/index", | 416 | "path": "pages/order_list/index", |
| 280 | "style": { | 417 | "style": { |
| 281 | "navigationBarTitleText": "订货单列表", | 418 | "navigationBarTitleText": "订货单列表", |
| @@ -152,12 +152,35 @@ export default { | @@ -152,12 +152,35 @@ export default { | ||
| 152 | }, | 152 | }, |
| 153 | { | 153 | { |
| 154 | text: '外贸客户资信管理', | 154 | text: '外贸客户资信管理', |
| 155 | - icon: '/static/images/index/order_list.png', | 155 | + icon: '/static/images/index/change_list.png', |
| 156 | link: '/pages/foreign_trade/index', | 156 | link: '/pages/foreign_trade/index', |
| 157 | name: 'ForeignTrade' | 157 | name: 'ForeignTrade' |
| 158 | + }, | ||
| 159 | + { | ||
| 160 | + text: '业务员报价单', | ||
| 161 | + icon: '/static/images/index/revoke_list.png', | ||
| 162 | + link: '/pages/sales-price/index', | ||
| 163 | + name: 'SalesPrice' | ||
| 164 | + }, | ||
| 165 | + { | ||
| 166 | + text: '报价项目', | ||
| 167 | + icon: '/static/images/index/invoice.png', | ||
| 168 | + link: '/pages/supplier-price/index', | ||
| 169 | + name: 'SupplierPrice' | ||
| 170 | + }, | ||
| 171 | + { | ||
| 172 | + text: '同行信息', | ||
| 173 | + icon: '/static/images/index/draft_order.png', | ||
| 174 | + link: '/pages/peer-info/index', | ||
| 175 | + name: 'PeerInfo' | ||
| 176 | + }, | ||
| 177 | + { | ||
| 178 | + text: '报价管理', | ||
| 179 | + icon: '/static/images/index/delay_invoice.png', | ||
| 180 | + link: '/pages/quote-manage/index', | ||
| 181 | + name: 'QuoteManage' | ||
| 158 | } | 182 | } |
| 159 | ] | 183 | ] |
| 160 | - | ||
| 161 | }, | 184 | }, |
| 162 | { | 185 | { |
| 163 | title: '订货单管理', | 186 | title: '订货单管理', |
pages/peer-info/add.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="page"> | ||
| 3 | + <scroll-view class="scroll" scroll-y> | ||
| 4 | + <uni-list> | ||
| 5 | + <uni-list-item> | ||
| 6 | + <template v-slot:body> | ||
| 7 | + <view class="item-title"><text class="required">*</text><text>同行名称</text></view> | ||
| 8 | + </template> | ||
| 9 | + <template v-slot:footer> | ||
| 10 | + <uni-easyinput v-model="form.peerName" placeholder="请输入同行名称" :inputBorder="false" /> | ||
| 11 | + </template> | ||
| 12 | + </uni-list-item> | ||
| 13 | + | ||
| 14 | + <uni-list-item class="select-item" :class="form.peerProductName ? 'is-filled' : 'is-empty'" clickable | ||
| 15 | + @click="openSheet('peerProductId')" :rightText="displayLabel('peerProductName')" showArrow> | ||
| 16 | + <template v-slot:body> | ||
| 17 | + <view class="item-title"><text class="required">*</text><text>同行品种</text></view> | ||
| 18 | + </template> | ||
| 19 | + </uni-list-item> | ||
| 20 | + | ||
| 21 | + <uni-list-item> | ||
| 22 | + <template v-slot:body> | ||
| 23 | + <view class="item-title"><text class="required">*</text><text>同行报价</text></view> | ||
| 24 | + </template> | ||
| 25 | + <template v-slot:footer> | ||
| 26 | + <uni-easyinput type="digit" v-model="form.peerPrice" placeholder="请输入同行报价" :inputBorder="false" /> | ||
| 27 | + </template> | ||
| 28 | + </uni-list-item> | ||
| 29 | + </uni-list> | ||
| 30 | + </scroll-view> | ||
| 31 | + | ||
| 32 | + <view class="footer"> | ||
| 33 | + <button class="btn submit" type="primary" :disabled="submitting" @click="onSubmit">{{ submitting ? '提交中...' : '提交' }}</button> | ||
| 34 | + </view> | ||
| 35 | + | ||
| 36 | + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" | ||
| 37 | + @confirm="onSheetConfirm" /> | ||
| 38 | + </view> | ||
| 39 | +</template> | ||
| 40 | + | ||
| 41 | +<script> | ||
| 42 | +import SingleSelectSheet from '@/components/single-select/index.vue' | ||
| 43 | +import { breedRelationshipQueryApi } from '@/api/procure-manage/salesmanQuotation.js' | ||
| 44 | +import { salesmanQuotationPeerSaveApi } from '@/api/procure-manage/salesmanQuotationPeer.js' | ||
| 45 | + | ||
| 46 | +export default { | ||
| 47 | + name: 'PeerInfoAdd', | ||
| 48 | + components: { SingleSelectSheet }, | ||
| 49 | + data() { | ||
| 50 | + return { | ||
| 51 | + submitting: false, | ||
| 52 | + productVarietyList: [], | ||
| 53 | + sheet: { visible: false, title: '请选择', options: [], field: '', value: '' }, | ||
| 54 | + form: { | ||
| 55 | + peerName: '', | ||
| 56 | + peerProductId: '', | ||
| 57 | + peerProductName: '', | ||
| 58 | + peerPrice: '' | ||
| 59 | + } | ||
| 60 | + } | ||
| 61 | + }, | ||
| 62 | + created() { | ||
| 63 | + this.loadProductVariety() | ||
| 64 | + }, | ||
| 65 | + methods: { | ||
| 66 | + async loadProductVariety() { | ||
| 67 | + try { | ||
| 68 | + const res = await breedRelationshipQueryApi({ pageIndex: 1, pageSize: 9999 }) | ||
| 69 | + const _data = res && res.data ? res.data : {} | ||
| 70 | + const list = _data.datas || _data.list || _data.records || [] | ||
| 71 | + this.productVarietyList = list.map(it => ({ | ||
| 72 | + label: it.productName || it.name || '', | ||
| 73 | + value: it.productId || it.id || '' | ||
| 74 | + })).filter(it => it.value) | ||
| 75 | + } catch (e) { | ||
| 76 | + this.productVarietyList = [] | ||
| 77 | + } | ||
| 78 | + }, | ||
| 79 | + displayLabel(field) { | ||
| 80 | + const map = { peerProductName: '请选择同行品种' } | ||
| 81 | + const val = this.form[field] | ||
| 82 | + return val ? String(val) : (map[field] || '请选择') | ||
| 83 | + }, | ||
| 84 | + openSheet(field) { | ||
| 85 | + if (field === 'peerProductId') { | ||
| 86 | + const current = this.form.peerProductId | ||
| 87 | + const match = (this.productVarietyList || []).find(o => String(o.value) === String(current)) | ||
| 88 | + this.sheet = { | ||
| 89 | + visible: true, | ||
| 90 | + title: '同行品种', | ||
| 91 | + options: this.productVarietyList || [], | ||
| 92 | + field, | ||
| 93 | + value: match ? match.value : '' | ||
| 94 | + } | ||
| 95 | + } | ||
| 96 | + }, | ||
| 97 | + onSheetConfirm({ value, label }) { | ||
| 98 | + const field = this.sheet.field | ||
| 99 | + if (!field) return | ||
| 100 | + if (field === 'peerProductId') { | ||
| 101 | + this.form.peerProductId = value || '' | ||
| 102 | + this.form.peerProductName = label || '' | ||
| 103 | + } | ||
| 104 | + }, | ||
| 105 | + validate() { | ||
| 106 | + const checks = [ | ||
| 107 | + { key: 'peerName', label: '同行名称' }, | ||
| 108 | + { key: 'peerProductId', label: '同行品种' }, | ||
| 109 | + { key: 'peerPrice', label: '同行报价' } | ||
| 110 | + ] | ||
| 111 | + for (const it of checks) { | ||
| 112 | + const val = this.form[it.key] | ||
| 113 | + const empty = (val === undefined || val === null || (typeof val === 'string' && String(val).trim() === '')) | ||
| 114 | + if (empty) { | ||
| 115 | + uni.showToast({ title: `${it.label}必填`, icon: 'none' }) | ||
| 116 | + return false | ||
| 117 | + } | ||
| 118 | + } | ||
| 119 | + return true | ||
| 120 | + }, | ||
| 121 | + buildPayload() { | ||
| 122 | + return { | ||
| 123 | + peerName: this.form.peerName, | ||
| 124 | + peerProductId: this.form.peerProductId, | ||
| 125 | + peerPrice: this.form.peerPrice | ||
| 126 | + } | ||
| 127 | + }, | ||
| 128 | + async onSubmit() { | ||
| 129 | + if (this.submitting) return | ||
| 130 | + if (!this.validate()) return | ||
| 131 | + this.submitting = true | ||
| 132 | + const payload = this.buildPayload() | ||
| 133 | + try { | ||
| 134 | + await salesmanQuotationPeerSaveApi(payload) | ||
| 135 | + uni.showToast({ title: '保存成功', icon: 'success' }) | ||
| 136 | + try { uni.setStorageSync('PEER_INFO_LIST_NEED_REFRESH', '1') } catch (e) {} | ||
| 137 | + setTimeout(() => { uni.redirectTo({ url: '/pages/peer-info/index' }) }, 300) | ||
| 138 | + } catch (e) { | ||
| 139 | + uni.showToast({ title: (e && e.msg) || '保存失败', icon: 'none' }) | ||
| 140 | + } finally { | ||
| 141 | + this.submitting = false | ||
| 142 | + } | ||
| 143 | + } | ||
| 144 | + } | ||
| 145 | +} | ||
| 146 | +</script> | ||
| 147 | + | ||
| 148 | +<style lang="scss" scoped> | ||
| 149 | +.page { | ||
| 150 | + display: flex; | ||
| 151 | + flex-direction: column; | ||
| 152 | + height: 100%; | ||
| 153 | +} | ||
| 154 | + | ||
| 155 | +.scroll { | ||
| 156 | + flex: 1; | ||
| 157 | + padding: 0rpx 0 160rpx; | ||
| 158 | + background-color: #f3f3f3; | ||
| 159 | +} | ||
| 160 | + | ||
| 161 | +.footer { | ||
| 162 | + position: fixed; | ||
| 163 | + left: 0; | ||
| 164 | + right: 0; | ||
| 165 | + bottom: 0; | ||
| 166 | + padding: 32rpx; | ||
| 167 | + padding-bottom: calc(32rpx + env(safe-area-inset-bottom)); | ||
| 168 | + background: #fff; | ||
| 169 | + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06); | ||
| 170 | + z-index: 10; | ||
| 171 | + | ||
| 172 | + .btn { | ||
| 173 | + height: 80rpx; | ||
| 174 | + line-height: 80rpx; | ||
| 175 | + border-radius: 12rpx; | ||
| 176 | + font-size: 32rpx; | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | + .submit { | ||
| 180 | + background: $theme-primary; | ||
| 181 | + color: #fff; | ||
| 182 | + } | ||
| 183 | +} | ||
| 184 | + | ||
| 185 | +.title-header { | ||
| 186 | + display: flex; | ||
| 187 | + align-items: center; | ||
| 188 | + padding: 24rpx 32rpx 12rpx; | ||
| 189 | + background-color: #ffffff; | ||
| 190 | + | ||
| 191 | + .title-header_icon { | ||
| 192 | + width: 36rpx; | ||
| 193 | + height: 36rpx; | ||
| 194 | + margin-right: 12rpx; | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + span { | ||
| 198 | + font-size: 34rpx; | ||
| 199 | + font-weight: 600; | ||
| 200 | + color: rgba(0, 0, 0, 0.9); | ||
| 201 | + } | ||
| 202 | +} | ||
| 203 | + | ||
| 204 | +.mgb10 { | ||
| 205 | + margin-bottom: 20rpx; | ||
| 206 | +} | ||
| 207 | + | ||
| 208 | +::v-deep .uni-list { | ||
| 209 | + .uni-easyinput { | ||
| 210 | + display: flex; | ||
| 211 | + | ||
| 212 | + .uni-input-input { | ||
| 213 | + color: rgba(0, 0, 0, 0.9); | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | + | ||
| 217 | + .uni-input-placeholder { | ||
| 218 | + z-index: 1; | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + .uni-input-input { | ||
| 222 | + background-color: #ffffff; | ||
| 223 | + } | ||
| 224 | + | ||
| 225 | + background: transparent; | ||
| 226 | + | ||
| 227 | + &-item { | ||
| 228 | + &__extra-text { | ||
| 229 | + font-size: 32rpx; | ||
| 230 | + } | ||
| 231 | + | ||
| 232 | + &__content-title { | ||
| 233 | + font-size: 32rpx; | ||
| 234 | + color: rgba(0, 0, 0, 0.9); | ||
| 235 | + } | ||
| 236 | + | ||
| 237 | + &__container { | ||
| 238 | + padding: 32rpx; | ||
| 239 | + | ||
| 240 | + .uni-easyinput { | ||
| 241 | + &__placeholder-class { | ||
| 242 | + font-size: 32rpx; | ||
| 243 | + color: rgba(0, 0, 0, 0.4); | ||
| 244 | + } | ||
| 245 | + | ||
| 246 | + &__content { | ||
| 247 | + border: none; | ||
| 248 | + background-color: #ffffff !important; | ||
| 249 | + | ||
| 250 | + &-input { | ||
| 251 | + padding-left: 0 !important; | ||
| 252 | + height: 48rpx; | ||
| 253 | + line-height: 48rpx; | ||
| 254 | + font-size: 32rpx; | ||
| 255 | + } | ||
| 256 | + | ||
| 257 | + .content-clear-icon { | ||
| 258 | + font-size: 44rpx !important; | ||
| 259 | + } | ||
| 260 | + } | ||
| 261 | + } | ||
| 262 | + | ||
| 263 | + .item-title, | ||
| 264 | + .uni-list-item__content { | ||
| 265 | + flex: none; | ||
| 266 | + min-height: 48rpx; | ||
| 267 | + line-height: 48rpx; | ||
| 268 | + font-size: 32rpx; | ||
| 269 | + position: relative; | ||
| 270 | + width: 210rpx; | ||
| 271 | + margin-right: 32rpx; | ||
| 272 | + color: rgba(0, 0, 0, 0.9); | ||
| 273 | + | ||
| 274 | + .required { | ||
| 275 | + color: red; | ||
| 276 | + position: absolute; | ||
| 277 | + top: 50%; | ||
| 278 | + transform: translateY(-50%); | ||
| 279 | + left: -16rpx; | ||
| 280 | + } | ||
| 281 | + } | ||
| 282 | + } | ||
| 283 | + | ||
| 284 | + &.select-item { | ||
| 285 | + &.is-empty { | ||
| 286 | + .uni-list-item__extra-text { | ||
| 287 | + color: rgba(0, 0, 0, 0.4) !important; | ||
| 288 | + } | ||
| 289 | + } | ||
| 290 | + | ||
| 291 | + &.is-filled { | ||
| 292 | + .uni-list-item__extra-text { | ||
| 293 | + color: rgba(0, 0, 0, 0.9) !important; | ||
| 294 | + } | ||
| 295 | + } | ||
| 296 | + } | ||
| 297 | + | ||
| 298 | + &.mgb10 { | ||
| 299 | + margin-bottom: 20rpx; | ||
| 300 | + } | ||
| 301 | + } | ||
| 302 | +} | ||
| 303 | +</style> |
pages/peer-info/detail.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="page"> | ||
| 3 | + <scroll-view class="scroll" scroll-y> | ||
| 4 | + <view class="detail-page"> | ||
| 5 | + <view class="section"> | ||
| 6 | + <text class="row company">{{ safeText(form.peerName) }}</text> | ||
| 7 | + <view class="row"><text class="label">同行品种</text><text class="value">{{ safeText(form.peerProductName) }}</text></view> | ||
| 8 | + <view class="row"><text class="label">同行报价</text><text class="value">{{ safeText(form.peerPrice) }}</text></view> | ||
| 9 | + <view class="row"><text class="label">创建人</text><text class="value">{{ safeText(form.createBy) }}</text></view> | ||
| 10 | + <view class="row"><text class="label">创建时间</text><text class="value">{{ formatDateTime(form.createTime) }}</text></view> | ||
| 11 | + </view> | ||
| 12 | + </view> | ||
| 13 | + </scroll-view> | ||
| 14 | + <detail-buttons :buttons="displayButtons" @click="handleButtonClick" /> | ||
| 15 | + </view> | ||
| 16 | +</template> | ||
| 17 | + | ||
| 18 | +<script> | ||
| 19 | +import DetailButtons from '@/components/detail-buttons/index.vue' | ||
| 20 | +import { salesmanQuotationPeerGetApi, salesmanQuotationPeerDeleteApi } from '@/api/procure-manage/salesmanQuotationPeer.js' | ||
| 21 | + | ||
| 22 | +export default { | ||
| 23 | + name: 'PeerInfoDetail', | ||
| 24 | + components: { DetailButtons }, | ||
| 25 | + data() { | ||
| 26 | + return { | ||
| 27 | + id: '', | ||
| 28 | + loading: false, | ||
| 29 | + form: {}, | ||
| 30 | + buttons: [ | ||
| 31 | + { text: '编辑', visible: true, variant: 'outline', event: 'edit' }, | ||
| 32 | + { text: '删除', visible: true, variant: 'danger', event: 'delete' } | ||
| 33 | + ] | ||
| 34 | + } | ||
| 35 | + }, | ||
| 36 | + computed: { | ||
| 37 | + displayButtons() { | ||
| 38 | + const isToday = this.isToday(this.form.createTime); | ||
| 39 | + return [ | ||
| 40 | + { ...this.buttons[0], visible: isToday && this.$auth.hasPermi('procure-manage:peer-info:modify') }, | ||
| 41 | + { ...this.buttons[1], visible: isToday && this.$auth.hasPermi('procure-manage:peer-info:delete') } | ||
| 42 | + ] | ||
| 43 | + } | ||
| 44 | + }, | ||
| 45 | + onShow() { | ||
| 46 | + const options = (this.$route && this.$route.query) ? this.$route.query : {} | ||
| 47 | + const id = options && options.id ? String(options.id) : '' | ||
| 48 | + if (id && id !== this.id) { | ||
| 49 | + this.id = id | ||
| 50 | + } | ||
| 51 | + if (this.id) this.loadDetail() | ||
| 52 | + }, | ||
| 53 | + methods: { | ||
| 54 | + isToday(dateStr) { | ||
| 55 | + if (!dateStr) return false; | ||
| 56 | + const date = new Date(dateStr); | ||
| 57 | + const today = new Date(); | ||
| 58 | + return ( | ||
| 59 | + date.getFullYear() === today.getFullYear() && | ||
| 60 | + date.getMonth() === today.getMonth() && | ||
| 61 | + date.getDate() === today.getDate() | ||
| 62 | + ); | ||
| 63 | + }, | ||
| 64 | + safeText(v) { | ||
| 65 | + const s = v == null ? '' : String(v) | ||
| 66 | + return s.trim() ? s : '' | ||
| 67 | + }, | ||
| 68 | + formatDateTime(v) { | ||
| 69 | + const s = v == null ? '' : String(v).trim() | ||
| 70 | + if (!s) return '-' | ||
| 71 | + if (s.length >= 16) return s.slice(0, 16) | ||
| 72 | + if (s.length >= 10) return s.slice(0, 10) | ||
| 73 | + return s | ||
| 74 | + }, | ||
| 75 | + handleButtonClick(btn) { | ||
| 76 | + if (!btn || btn.disabled) return | ||
| 77 | + const e = btn.event || '' | ||
| 78 | + if (e === 'edit') return this.onEdit() | ||
| 79 | + if (e === 'delete') return this.onDelete() | ||
| 80 | + }, | ||
| 81 | + onEdit() { | ||
| 82 | + uni.navigateTo({ url: '/pages/peer-info/modify?id=' + this.id }) | ||
| 83 | + }, | ||
| 84 | + onDelete() { | ||
| 85 | + const id = this.id || (this.form && this.form.id) || '' | ||
| 86 | + if (!id) return | ||
| 87 | + uni.showModal({ | ||
| 88 | + title: '系统提示', | ||
| 89 | + content: '是否确定删除该同行信息?', | ||
| 90 | + confirmText: '确定', | ||
| 91 | + cancelText: '取消', | ||
| 92 | + success: (res) => { | ||
| 93 | + if (res && res.confirm) { | ||
| 94 | + salesmanQuotationPeerDeleteApi(id).then(() => { | ||
| 95 | + uni.showToast({ title: '已删除', icon: 'none' }) | ||
| 96 | + try { uni.setStorageSync('PEER_INFO_LIST_NEED_REFRESH', '1') } catch (e) {} | ||
| 97 | + setTimeout(() => { uni.redirectTo({ url: '/pages/peer-info/index' }) }, 300) | ||
| 98 | + }).catch((e) => { | ||
| 99 | + uni.showToast({ title: (e && e.msg) || '删除失败', icon: 'none' }) | ||
| 100 | + }) | ||
| 101 | + } | ||
| 102 | + } | ||
| 103 | + }) | ||
| 104 | + }, | ||
| 105 | + async loadDetail() { | ||
| 106 | + this.loading = true | ||
| 107 | + try { | ||
| 108 | + const res = await salesmanQuotationPeerGetApi(this.id) | ||
| 109 | + this.form = (res && res.data) ? res.data : {} | ||
| 110 | + } catch (e) { | ||
| 111 | + this.form = {} | ||
| 112 | + uni.showToast({ title: '详情加载失败', icon: 'none' }) | ||
| 113 | + } finally { | ||
| 114 | + this.loading = false | ||
| 115 | + } | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | +} | ||
| 119 | +</script> | ||
| 120 | + | ||
| 121 | +<style lang="scss" scoped> | ||
| 122 | +.page { | ||
| 123 | + display: flex; | ||
| 124 | + flex-direction: column; | ||
| 125 | + height: 100%; | ||
| 126 | +} | ||
| 127 | + | ||
| 128 | +.scroll { | ||
| 129 | + flex: 1; | ||
| 130 | + padding: 8rpx 0 144rpx; | ||
| 131 | +} | ||
| 132 | + | ||
| 133 | +.detail-page { | ||
| 134 | + background: #f3f3f3; | ||
| 135 | +} | ||
| 136 | + | ||
| 137 | +.section { | ||
| 138 | + padding: 32rpx; | ||
| 139 | + background: #fff; | ||
| 140 | + margin-bottom: 20rpx; | ||
| 141 | +} | ||
| 142 | + | ||
| 143 | +.row { | ||
| 144 | + display: flex; | ||
| 145 | + margin-bottom: 28rpx; | ||
| 146 | + | ||
| 147 | + &:last-child { | ||
| 148 | + margin-bottom: 0; | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + &.company { | ||
| 152 | + font-size: 36rpx; | ||
| 153 | + font-weight: 600; | ||
| 154 | + color: rgba(0, 0, 0, 0.9); | ||
| 155 | + padding-top: 8rpx; | ||
| 156 | + line-height: 50rpx; | ||
| 157 | + margin-bottom: 28rpx; | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + .label { | ||
| 161 | + max-width: 420rpx; | ||
| 162 | + margin-right: 20rpx; | ||
| 163 | + line-height: 32rpx; | ||
| 164 | + font-size: 28rpx; | ||
| 165 | + color: rgba(0, 0, 0, 0.6); | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + .value { | ||
| 169 | + flex: 1; | ||
| 170 | + line-height: 32rpx; | ||
| 171 | + font-size: 28rpx; | ||
| 172 | + color: rgba(0, 0, 0, 0.9); | ||
| 173 | + text-align: right; | ||
| 174 | + word-break: break-all; | ||
| 175 | + | ||
| 176 | + &.pre { | ||
| 177 | + white-space: pre-wrap; | ||
| 178 | + } | ||
| 179 | + } | ||
| 180 | +} | ||
| 181 | +</style> |
pages/peer-info/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="page"> | ||
| 3 | + <view class="dev-list-fixed"> | ||
| 4 | + <view class="search-row"> | ||
| 5 | + <uni-search-bar v-model="searchKeyword" radius="6" placeholder="请输入同行名称" clearButton="auto" | ||
| 6 | + cancelButton="none" bgColor="#F3F3F3" textColor="rgba(0,0,0,0.4)" @confirm="search" | ||
| 7 | + @input="onSearchInput" /> | ||
| 8 | + <view class="tool-icons"> | ||
| 9 | + <image class="tool-icon" src="/static/images/dev_manage/add_icon.png" @click="onAdd" /> | ||
| 10 | + <image class="tool-icon" src="/static/images/dev_manage/filter_icon.png" @click="openFilter" /> | ||
| 11 | + </view> | ||
| 12 | + </view> | ||
| 13 | + </view> | ||
| 14 | + | ||
| 15 | + <view class="list-box"> | ||
| 16 | + <card-list ref="cardRef" :fetch-fn="fetchList" :query="query" :extra="extraParams" row-key="id" | ||
| 17 | + :enable-refresh="true" :enable-load-more="true" @loaded="onCardLoaded" @error="onCardError"> | ||
| 18 | + <template v-slot="{ item }"> | ||
| 19 | + <view class="card" @click.stop="onCardClick(item)"> | ||
| 20 | + <view class="card-header"> | ||
| 21 | + <text class="title omit2">{{ item.peerName || '-' }}</text> | ||
| 22 | + </view> | ||
| 23 | + <view class="info-row"> | ||
| 24 | + <text>同行品种</text><text>{{ item.peerProductName || '-' }}</text> | ||
| 25 | + </view> | ||
| 26 | + <view class="info-row"> | ||
| 27 | + <text>同行报价</text><text>{{ item.peerPrice != null ? item.peerPrice : '-' }}</text> | ||
| 28 | + </view> | ||
| 29 | + <view class="info-row"> | ||
| 30 | + <text>创建人</text><text>{{ item.createBy || '-' }}</text> | ||
| 31 | + </view> | ||
| 32 | + <view class="info-row"> | ||
| 33 | + <text>创建时间</text><text>{{ formatDateTime(item.createTime) }}</text> | ||
| 34 | + </view> | ||
| 35 | + </view> | ||
| 36 | + </template> | ||
| 37 | + </card-list> | ||
| 38 | + </view> | ||
| 39 | + | ||
| 40 | + <filter-modal :visible.sync="filterVisible" :value.sync="filterForm" title="筛选" @reset="onFilterReset" | ||
| 41 | + @confirm="onFilterConfirm"> | ||
| 42 | + <template v-slot="{ model }"> | ||
| 43 | + <view class="filter-form"> | ||
| 44 | + <view class="form-item"> | ||
| 45 | + <view class="label">同行名称</view> | ||
| 46 | + <uni-easyinput v-model="model.peerName" placeholder="请输入同行名称" :inputBorder="false" | ||
| 47 | + placeholderStyle="font-size:14px" @input="onPeerNameInput" /> | ||
| 48 | + </view> | ||
| 49 | + <view class="form-item"> | ||
| 50 | + <view class="label">同行品种名称</view> | ||
| 51 | + <uni-easyinput v-model="model.peerProductName" placeholder="请输入同行品种名称" :inputBorder="false" | ||
| 52 | + placeholderStyle="font-size:14px" @input="onPeerProductNameInput" /> | ||
| 53 | + </view> | ||
| 54 | + <view class="form-item"> | ||
| 55 | + <view class="label">创建日期</view> | ||
| 56 | + <uni-datetime-picker type="daterange" v-model="model.dateRange" start="2023-01-01" /> | ||
| 57 | + </view> | ||
| 58 | + </view> | ||
| 59 | + </template> | ||
| 60 | + </filter-modal> | ||
| 61 | + </view> | ||
| 62 | +</template> | ||
| 63 | + | ||
| 64 | +<script> | ||
| 65 | +import CardList from '@/components/card/index.vue' | ||
| 66 | +import FilterModal from '@/components/filter/index.vue' | ||
| 67 | +import { salesmanQuotationPeerQueryApi } from '@/api/procure-manage/salesmanQuotationPeer.js' | ||
| 68 | + | ||
| 69 | +export default { | ||
| 70 | + name: 'PeerInfoList', | ||
| 71 | + components: { CardList, FilterModal }, | ||
| 72 | + data() { | ||
| 73 | + return { | ||
| 74 | + searchKeyword: '', | ||
| 75 | + searchKeywordDebounced: '', | ||
| 76 | + searchDebounceTimer: null, | ||
| 77 | + query: { | ||
| 78 | + peerName: '', | ||
| 79 | + peerProductName: '', | ||
| 80 | + dateRange: [] | ||
| 81 | + }, | ||
| 82 | + extraParams: {}, | ||
| 83 | + currentItems: [], | ||
| 84 | + filterVisible: false, | ||
| 85 | + filterForm: { | ||
| 86 | + peerName: '', | ||
| 87 | + peerProductName: '', | ||
| 88 | + dateRange: [] | ||
| 89 | + } | ||
| 90 | + } | ||
| 91 | + }, | ||
| 92 | + watch: { | ||
| 93 | + searchKeywordDebounced(v) { | ||
| 94 | + this.query = { ...this.query, peerName: v || '' } | ||
| 95 | + } | ||
| 96 | + }, | ||
| 97 | + onShow() { | ||
| 98 | + let needRefresh = '' | ||
| 99 | + try { needRefresh = uni.getStorageSync('PEER_INFO_LIST_NEED_REFRESH') } catch (e) {} | ||
| 100 | + if (!needRefresh) return | ||
| 101 | + try { uni.removeStorageSync('PEER_INFO_LIST_NEED_REFRESH') } catch (e) {} | ||
| 102 | + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.reload) { | ||
| 103 | + this.$refs.cardRef.reload() | ||
| 104 | + } | ||
| 105 | + }, | ||
| 106 | + onReachBottom() { | ||
| 107 | + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) { | ||
| 108 | + this.$refs.cardRef.onLoadMore() | ||
| 109 | + } | ||
| 110 | + }, | ||
| 111 | + beforeDestroy() { | ||
| 112 | + if (this.searchDebounceTimer) { | ||
| 113 | + clearTimeout(this.searchDebounceTimer) | ||
| 114 | + this.searchDebounceTimer = null | ||
| 115 | + } | ||
| 116 | + }, | ||
| 117 | + methods: { | ||
| 118 | + formatDateTime(v) { | ||
| 119 | + const s = v == null ? '' : String(v).trim() | ||
| 120 | + if (!s) return '-' | ||
| 121 | + if (s.length >= 16) return s.slice(0, 16) | ||
| 122 | + if (s.length >= 10) return s.slice(0, 10) | ||
| 123 | + return s | ||
| 124 | + }, | ||
| 125 | + onAdd() { | ||
| 126 | + uni.navigateTo({ url: '/pages/peer-info/add' }) | ||
| 127 | + }, | ||
| 128 | + onCardLoaded({ items }) { | ||
| 129 | + this.currentItems = items | ||
| 130 | + }, | ||
| 131 | + onCardError() { | ||
| 132 | + uni.showToast({ title: '列表加载失败', icon: 'none' }) | ||
| 133 | + }, | ||
| 134 | + onSearchInput() { | ||
| 135 | + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer) | ||
| 136 | + this.searchDebounceTimer = setTimeout(() => { | ||
| 137 | + this.searchKeywordDebounced = this.searchKeyword | ||
| 138 | + this.searchDebounceTimer = null | ||
| 139 | + }, 1200) | ||
| 140 | + }, | ||
| 141 | + search(e) { | ||
| 142 | + const val = e && e.value != null ? e.value : this.searchKeyword | ||
| 143 | + this.searchKeyword = val | ||
| 144 | + this.searchKeywordDebounced = val | ||
| 145 | + }, | ||
| 146 | + openFilter() { | ||
| 147 | + this.filterForm = { | ||
| 148 | + peerName: this.query.peerName || '', | ||
| 149 | + peerProductName: this.query.peerProductName || '', | ||
| 150 | + dateRange: Array.isArray(this.query.dateRange) ? this.query.dateRange.slice(0) : [] | ||
| 151 | + } | ||
| 152 | + this.filterVisible = true | ||
| 153 | + }, | ||
| 154 | + onFilterReset(payload) { | ||
| 155 | + this.filterForm = payload | ||
| 156 | + }, | ||
| 157 | + onFilterConfirm(payload) { | ||
| 158 | + this.query = { | ||
| 159 | + peerName: this.searchKeywordDebounced || payload.peerName || '', | ||
| 160 | + peerProductName: payload.peerProductName || '', | ||
| 161 | + dateRange: Array.isArray(payload.dateRange) ? payload.dateRange : [] | ||
| 162 | + } | ||
| 163 | + }, | ||
| 164 | + onPeerNameInput(val) { | ||
| 165 | + this.filterForm.peerName = val | ||
| 166 | + }, | ||
| 167 | + onPeerProductNameInput(val) { | ||
| 168 | + this.filterForm.peerProductName = val | ||
| 169 | + }, | ||
| 170 | + fetchList({ pageIndex, pageSize, query }) { | ||
| 171 | + const q = query || {} | ||
| 172 | + const range = Array.isArray(q.dateRange) ? q.dateRange : [] | ||
| 173 | + const params = { | ||
| 174 | + pageIndex, | ||
| 175 | + pageSize, | ||
| 176 | + peerName: q.peerName || '', | ||
| 177 | + peerProductName: q.peerProductName || '', | ||
| 178 | + createDateStart: (range && range.length === 2) ? range[0] : '', | ||
| 179 | + createDateEnd: (range && range.length === 2) ? range[1] : '' | ||
| 180 | + } | ||
| 181 | + return salesmanQuotationPeerQueryApi(params).then(res => { | ||
| 182 | + const _data = res && res.data ? res.data : {} | ||
| 183 | + let records = _data.datas || _data.list || _data.records || [] | ||
| 184 | + const totalCount = _data.totalCount || _data.count || 0 | ||
| 185 | + const hasNext = _data.hasNext || false | ||
| 186 | + records = records.map(it => ({ ...it })) | ||
| 187 | + return { records, totalCount, hasNext } | ||
| 188 | + }).catch(() => { | ||
| 189 | + this.onCardError() | ||
| 190 | + return { records: [], totalCount: 0, hasNext: false } | ||
| 191 | + }) | ||
| 192 | + }, | ||
| 193 | + onCardClick(item) { | ||
| 194 | + uni.navigateTo({ url: '/pages/peer-info/detail?id=' + item.id }) | ||
| 195 | + } | ||
| 196 | + } | ||
| 197 | +} | ||
| 198 | +</script> | ||
| 199 | + | ||
| 200 | +<style lang="scss" scoped> | ||
| 201 | +.page { | ||
| 202 | + display: flex; | ||
| 203 | + flex-direction: column; | ||
| 204 | + height: 100vh; | ||
| 205 | +} | ||
| 206 | + | ||
| 207 | +.dev-list-fixed { | ||
| 208 | + position: fixed; | ||
| 209 | + top: 96rpx; | ||
| 210 | + left: 0; | ||
| 211 | + right: 0; | ||
| 212 | + z-index: 2; | ||
| 213 | + background: #fff; | ||
| 214 | + | ||
| 215 | + .search-row { | ||
| 216 | + display: flex; | ||
| 217 | + align-items: center; | ||
| 218 | + padding: 16rpx 32rpx; | ||
| 219 | + | ||
| 220 | + .uni-searchbar { | ||
| 221 | + padding: 0; | ||
| 222 | + flex: 1; | ||
| 223 | + } | ||
| 224 | + | ||
| 225 | + .tool-icons { | ||
| 226 | + display: flex; | ||
| 227 | + | ||
| 228 | + .tool-icon { | ||
| 229 | + width: 48rpx; | ||
| 230 | + height: 48rpx; | ||
| 231 | + display: block; | ||
| 232 | + margin-left: 32rpx; | ||
| 233 | + } | ||
| 234 | + } | ||
| 235 | + } | ||
| 236 | +} | ||
| 237 | + | ||
| 238 | +::v-deep .uni-searchbar__box { | ||
| 239 | + height: 80rpx !important; | ||
| 240 | + justify-content: start; | ||
| 241 | + | ||
| 242 | + .uni-searchbar__box-search-input { | ||
| 243 | + font-size: 32rpx !important; | ||
| 244 | + } | ||
| 245 | +} | ||
| 246 | + | ||
| 247 | +.list-box { | ||
| 248 | + flex: 1; | ||
| 249 | + padding-top: 140rpx; | ||
| 250 | + | ||
| 251 | + .card { | ||
| 252 | + position: relative; | ||
| 253 | + } | ||
| 254 | + | ||
| 255 | + .card-header { | ||
| 256 | + margin-bottom: 28rpx; | ||
| 257 | + position: relative; | ||
| 258 | + | ||
| 259 | + .title { | ||
| 260 | + font-size: 36rpx; | ||
| 261 | + font-weight: 600; | ||
| 262 | + line-height: 50rpx; | ||
| 263 | + color: rgba(0, 0, 0, 0.9); | ||
| 264 | + width: 100%; | ||
| 265 | + } | ||
| 266 | + } | ||
| 267 | + | ||
| 268 | + .info-row { | ||
| 269 | + display: flex; | ||
| 270 | + align-items: center; | ||
| 271 | + color: rgba(0, 0, 0, 0.6); | ||
| 272 | + font-size: 28rpx; | ||
| 273 | + margin-bottom: 24rpx; | ||
| 274 | + height: 32rpx; | ||
| 275 | + | ||
| 276 | + &:last-child { | ||
| 277 | + margin-bottom: 0; | ||
| 278 | + } | ||
| 279 | + | ||
| 280 | + text { | ||
| 281 | + width: 50%; | ||
| 282 | + | ||
| 283 | + &:last-child { | ||
| 284 | + color: rgba(0, 0, 0, 0.9); | ||
| 285 | + width: 50%; | ||
| 286 | + } | ||
| 287 | + } | ||
| 288 | + } | ||
| 289 | +} | ||
| 290 | + | ||
| 291 | +.filter-form { | ||
| 292 | + .form-item { | ||
| 293 | + margin-bottom: 24rpx; | ||
| 294 | + } | ||
| 295 | + | ||
| 296 | + .label { | ||
| 297 | + margin-bottom: 20rpx; | ||
| 298 | + color: rgba(0, 0, 0, 0.9); | ||
| 299 | + height: 44rpx; | ||
| 300 | + line-height: 44rpx; | ||
| 301 | + font-size: 30rpx; | ||
| 302 | + } | ||
| 303 | + | ||
| 304 | + .uni-easyinput { | ||
| 305 | + border: 1rpx solid #f3f3f3; | ||
| 306 | + } | ||
| 307 | +} | ||
| 308 | +</style> |
pages/peer-info/modify.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="page"> | ||
| 3 | + <scroll-view class="scroll" scroll-y> | ||
| 4 | + <uni-list> | ||
| 5 | + <view class="title-header"> | ||
| 6 | + <image class="title-header_icon" src="/static/images/title.png" /> | ||
| 7 | + <span>同行信息</span> | ||
| 8 | + </view> | ||
| 9 | + | ||
| 10 | + <uni-list-item> | ||
| 11 | + <template v-slot:body> | ||
| 12 | + <view class="item-title"><text class="required">*</text><text>同行名称</text></view> | ||
| 13 | + </template> | ||
| 14 | + <template v-slot:footer> | ||
| 15 | + <uni-easyinput v-model="form.peerName" placeholder="请输入同行名称" :inputBorder="false" /> | ||
| 16 | + </template> | ||
| 17 | + </uni-list-item> | ||
| 18 | + | ||
| 19 | + <uni-list-item class="select-item" :class="form.peerProductName ? 'is-filled' : 'is-empty'" clickable | ||
| 20 | + @click="openSheet('peerProductId')" :rightText="displayLabel('peerProductName')" showArrow> | ||
| 21 | + <template v-slot:body> | ||
| 22 | + <view class="item-title"><text class="required">*</text><text>同行品种</text></view> | ||
| 23 | + </template> | ||
| 24 | + </uni-list-item> | ||
| 25 | + | ||
| 26 | + <uni-list-item> | ||
| 27 | + <template v-slot:body> | ||
| 28 | + <view class="item-title"><text class="required">*</text><text>同行报价</text></view> | ||
| 29 | + </template> | ||
| 30 | + <template v-slot:footer> | ||
| 31 | + <uni-easyinput type="digit" v-model="form.peerPrice" placeholder="请输入同行报价" :inputBorder="false" /> | ||
| 32 | + </template> | ||
| 33 | + </uni-list-item> | ||
| 34 | + </uni-list> | ||
| 35 | + </scroll-view> | ||
| 36 | + | ||
| 37 | + <view class="footer"> | ||
| 38 | + <button class="btn submit" type="primary" :disabled="submitting" @click="onSubmit">{{ submitting ? '提交中...' : '提交' }}</button> | ||
| 39 | + </view> | ||
| 40 | + | ||
| 41 | + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" | ||
| 42 | + @confirm="onSheetConfirm" /> | ||
| 43 | + </view> | ||
| 44 | +</template> | ||
| 45 | + | ||
| 46 | +<script> | ||
| 47 | +import SingleSelectSheet from '@/components/single-select/index.vue' | ||
| 48 | +import { breedRelationshipQueryApi } from '@/api/procure-manage/salesmanQuotation.js' | ||
| 49 | +import { salesmanQuotationPeerGetApi, salesmanQuotationPeerUpdateApi } from '@/api/procure-manage/salesmanQuotationPeer.js' | ||
| 50 | + | ||
| 51 | +export default { | ||
| 52 | + name: 'PeerInfoModify', | ||
| 53 | + components: { SingleSelectSheet }, | ||
| 54 | + data() { | ||
| 55 | + return { | ||
| 56 | + id: '', | ||
| 57 | + submitting: false, | ||
| 58 | + loading: false, | ||
| 59 | + productVarietyList: [], | ||
| 60 | + sheet: { visible: false, title: '请选择', options: [], field: '', value: '' }, | ||
| 61 | + form: { | ||
| 62 | + id: '', | ||
| 63 | + peerName: '', | ||
| 64 | + peerProductId: '', | ||
| 65 | + peerProductName: '', | ||
| 66 | + peerPrice: '' | ||
| 67 | + } | ||
| 68 | + } | ||
| 69 | + }, | ||
| 70 | + onLoad(query) { | ||
| 71 | + this.id = (query && query.id) ? String(query.id) : '' | ||
| 72 | + }, | ||
| 73 | + created() { | ||
| 74 | + this.loadProductVariety() | ||
| 75 | + if (this.id) this.loadDetail() | ||
| 76 | + }, | ||
| 77 | + methods: { | ||
| 78 | + async loadProductVariety() { | ||
| 79 | + try { | ||
| 80 | + const res = await breedRelationshipQueryApi({ pageIndex: 1, pageSize: 9999 }) | ||
| 81 | + const _data = res && res.data ? res.data : {} | ||
| 82 | + const list = _data.datas || _data.list || _data.records || [] | ||
| 83 | + this.productVarietyList = list.map(it => ({ | ||
| 84 | + label: it.productName || it.name || '', | ||
| 85 | + value: it.productId || it.id || '' | ||
| 86 | + })).filter(it => it.value) | ||
| 87 | + } catch (e) { | ||
| 88 | + this.productVarietyList = [] | ||
| 89 | + } | ||
| 90 | + }, | ||
| 91 | + async loadDetail() { | ||
| 92 | + this.loading = true | ||
| 93 | + try { | ||
| 94 | + const res = await salesmanQuotationPeerGetApi(this.id) | ||
| 95 | + const data = (res && res.data) ? res.data : {} | ||
| 96 | + this.form = { | ||
| 97 | + id: data.id || this.id, | ||
| 98 | + peerName: data.peerName || '', | ||
| 99 | + peerProductId: data.peerProductId || '', | ||
| 100 | + peerProductName: data.peerProductName || this.getOptionLabel(this.productVarietyList, data.peerProductId), | ||
| 101 | + peerPrice: data.peerPrice != null ? String(data.peerPrice) : '' | ||
| 102 | + } | ||
| 103 | + } catch (e) { | ||
| 104 | + uni.showToast({ title: '加载失败', icon: 'none' }) | ||
| 105 | + } finally { | ||
| 106 | + this.loading = false | ||
| 107 | + } | ||
| 108 | + }, | ||
| 109 | + getOptionLabel(options, value) { | ||
| 110 | + const v = value != null ? String(value) : '' | ||
| 111 | + if (!v) return '' | ||
| 112 | + const match = (options || []).find(o => String(o.value) === v) | ||
| 113 | + return match ? String(match.label || '') : '' | ||
| 114 | + }, | ||
| 115 | + displayLabel(field) { | ||
| 116 | + const map = { peerProductName: '请选择同行品种' } | ||
| 117 | + const val = this.form[field] | ||
| 118 | + return val ? String(val) : (map[field] || '请选择') | ||
| 119 | + }, | ||
| 120 | + openSheet(field) { | ||
| 121 | + if (field === 'peerProductId') { | ||
| 122 | + const current = this.form.peerProductId | ||
| 123 | + const match = (this.productVarietyList || []).find(o => String(o.value) === String(current)) | ||
| 124 | + this.sheet = { | ||
| 125 | + visible: true, | ||
| 126 | + title: '同行品种', | ||
| 127 | + options: this.productVarietyList || [], | ||
| 128 | + field, | ||
| 129 | + value: match ? match.value : '' | ||
| 130 | + } | ||
| 131 | + } | ||
| 132 | + }, | ||
| 133 | + onSheetConfirm({ value, label }) { | ||
| 134 | + const field = this.sheet.field | ||
| 135 | + if (!field) return | ||
| 136 | + if (field === 'peerProductId') { | ||
| 137 | + this.form.peerProductId = value || '' | ||
| 138 | + this.form.peerProductName = label || '' | ||
| 139 | + } | ||
| 140 | + }, | ||
| 141 | + validate() { | ||
| 142 | + const checks = [ | ||
| 143 | + { key: 'peerName', label: '同行名称' }, | ||
| 144 | + { key: 'peerProductId', label: '同行品种' }, | ||
| 145 | + { key: 'peerPrice', label: '同行报价' } | ||
| 146 | + ] | ||
| 147 | + for (const it of checks) { | ||
| 148 | + const val = this.form[it.key] | ||
| 149 | + const empty = (val === undefined || val === null || (typeof val === 'string' && String(val).trim() === '')) | ||
| 150 | + if (empty) { | ||
| 151 | + uni.showToast({ title: `${it.label}必填`, icon: 'none' }) | ||
| 152 | + return false | ||
| 153 | + } | ||
| 154 | + } | ||
| 155 | + return true | ||
| 156 | + }, | ||
| 157 | + buildPayload() { | ||
| 158 | + return { | ||
| 159 | + id: this.form.id, | ||
| 160 | + peerName: this.form.peerName, | ||
| 161 | + peerProductId: this.form.peerProductId, | ||
| 162 | + peerPrice: this.form.peerPrice | ||
| 163 | + } | ||
| 164 | + }, | ||
| 165 | + async onSubmit() { | ||
| 166 | + if (this.submitting) return | ||
| 167 | + if (!this.validate()) return | ||
| 168 | + this.submitting = true | ||
| 169 | + const payload = this.buildPayload() | ||
| 170 | + try { | ||
| 171 | + await salesmanQuotationPeerUpdateApi(payload) | ||
| 172 | + uni.showToast({ title: '保存成功', icon: 'success' }) | ||
| 173 | + try { uni.setStorageSync('PEER_INFO_LIST_NEED_REFRESH', '1') } catch (e) {} | ||
| 174 | + setTimeout(() => { uni.redirectTo({ url: '/pages/peer-info/index' }) }, 300) | ||
| 175 | + } catch (e) { | ||
| 176 | + uni.showToast({ title: (e && e.msg) || '保存失败', icon: 'none' }) | ||
| 177 | + } finally { | ||
| 178 | + this.submitting = false | ||
| 179 | + } | ||
| 180 | + } | ||
| 181 | + } | ||
| 182 | +} | ||
| 183 | +</script> | ||
| 184 | + | ||
| 185 | +<style lang="scss" scoped> | ||
| 186 | +.page { | ||
| 187 | + display: flex; | ||
| 188 | + flex-direction: column; | ||
| 189 | + height: 100%; | ||
| 190 | +} | ||
| 191 | + | ||
| 192 | +.scroll { | ||
| 193 | + flex: 1; | ||
| 194 | + padding: 0rpx 0 160rpx; | ||
| 195 | + background-color: #f3f3f3; | ||
| 196 | +} | ||
| 197 | + | ||
| 198 | +.footer { | ||
| 199 | + position: fixed; | ||
| 200 | + left: 0; | ||
| 201 | + right: 0; | ||
| 202 | + bottom: 0; | ||
| 203 | + padding: 32rpx; | ||
| 204 | + padding-bottom: calc(32rpx + env(safe-area-inset-bottom)); | ||
| 205 | + background: #fff; | ||
| 206 | + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06); | ||
| 207 | + z-index: 10; | ||
| 208 | + | ||
| 209 | + .btn { | ||
| 210 | + height: 80rpx; | ||
| 211 | + line-height: 80rpx; | ||
| 212 | + border-radius: 12rpx; | ||
| 213 | + font-size: 32rpx; | ||
| 214 | + } | ||
| 215 | + | ||
| 216 | + .submit { | ||
| 217 | + background: $theme-primary; | ||
| 218 | + color: #fff; | ||
| 219 | + } | ||
| 220 | +} | ||
| 221 | + | ||
| 222 | +.title-header { | ||
| 223 | + display: flex; | ||
| 224 | + align-items: center; | ||
| 225 | + padding: 24rpx 32rpx 12rpx; | ||
| 226 | + background-color: #ffffff; | ||
| 227 | + | ||
| 228 | + .title-header_icon { | ||
| 229 | + width: 36rpx; | ||
| 230 | + height: 36rpx; | ||
| 231 | + margin-right: 12rpx; | ||
| 232 | + } | ||
| 233 | + | ||
| 234 | + span { | ||
| 235 | + font-size: 34rpx; | ||
| 236 | + font-weight: 600; | ||
| 237 | + color: rgba(0, 0, 0, 0.9); | ||
| 238 | + } | ||
| 239 | +} | ||
| 240 | + | ||
| 241 | +.mgb10 { | ||
| 242 | + margin-bottom: 20rpx; | ||
| 243 | +} | ||
| 244 | + | ||
| 245 | +::v-deep .uni-list { | ||
| 246 | + .uni-easyinput { | ||
| 247 | + display: flex; | ||
| 248 | + | ||
| 249 | + .uni-input-input { | ||
| 250 | + color: rgba(0, 0, 0, 0.9); | ||
| 251 | + } | ||
| 252 | + } | ||
| 253 | + | ||
| 254 | + .uni-input-placeholder { | ||
| 255 | + z-index: 1; | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + .uni-input-input { | ||
| 259 | + background-color: #ffffff; | ||
| 260 | + } | ||
| 261 | + | ||
| 262 | + background: transparent; | ||
| 263 | + | ||
| 264 | + &-item { | ||
| 265 | + &__extra-text { | ||
| 266 | + font-size: 32rpx; | ||
| 267 | + } | ||
| 268 | + | ||
| 269 | + &__content-title { | ||
| 270 | + font-size: 32rpx; | ||
| 271 | + color: rgba(0, 0, 0, 0.9); | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + &__container { | ||
| 275 | + padding: 32rpx; | ||
| 276 | + | ||
| 277 | + .uni-easyinput { | ||
| 278 | + &__placeholder-class { | ||
| 279 | + font-size: 32rpx; | ||
| 280 | + color: rgba(0, 0, 0, 0.4); | ||
| 281 | + } | ||
| 282 | + | ||
| 283 | + &__content { | ||
| 284 | + border: none; | ||
| 285 | + background-color: #ffffff !important; | ||
| 286 | + | ||
| 287 | + &-input { | ||
| 288 | + padding-left: 0 !important; | ||
| 289 | + height: 48rpx; | ||
| 290 | + line-height: 48rpx; | ||
| 291 | + font-size: 32rpx; | ||
| 292 | + } | ||
| 293 | + | ||
| 294 | + .content-clear-icon { | ||
| 295 | + font-size: 44rpx !important; | ||
| 296 | + } | ||
| 297 | + } | ||
| 298 | + } | ||
| 299 | + | ||
| 300 | + .item-title, | ||
| 301 | + .uni-list-item__content { | ||
| 302 | + flex: none; | ||
| 303 | + min-height: 48rpx; | ||
| 304 | + line-height: 48rpx; | ||
| 305 | + font-size: 32rpx; | ||
| 306 | + position: relative; | ||
| 307 | + width: 210rpx; | ||
| 308 | + margin-right: 32rpx; | ||
| 309 | + color: rgba(0, 0, 0, 0.9); | ||
| 310 | + | ||
| 311 | + .required { | ||
| 312 | + color: red; | ||
| 313 | + position: absolute; | ||
| 314 | + top: 50%; | ||
| 315 | + transform: translateY(-50%); | ||
| 316 | + left: -16rpx; | ||
| 317 | + } | ||
| 318 | + } | ||
| 319 | + } | ||
| 320 | + | ||
| 321 | + &.select-item { | ||
| 322 | + &.is-empty { | ||
| 323 | + .uni-list-item__extra-text { | ||
| 324 | + color: rgba(0, 0, 0, 0.4) !important; | ||
| 325 | + } | ||
| 326 | + } | ||
| 327 | + | ||
| 328 | + &.is-filled { | ||
| 329 | + .uni-list-item__extra-text { | ||
| 330 | + color: rgba(0, 0, 0, 0.9) !important; | ||
| 331 | + } | ||
| 332 | + } | ||
| 333 | + } | ||
| 334 | + | ||
| 335 | + &.mgb10 { | ||
| 336 | + margin-bottom: 20rpx; | ||
| 337 | + } | ||
| 338 | + } | ||
| 339 | +} | ||
| 340 | +</style> |
pages/quote-manage/assign.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="page"> | ||
| 3 | + <scroll-view class="scroll" scroll-y> | ||
| 4 | + <view class="section" v-if="users.length > 0"> | ||
| 5 | + <view | ||
| 6 | + v-for="it in users" | ||
| 7 | + :key="it.id" | ||
| 8 | + class="card" | ||
| 9 | + :class="{ 'is-selected': selectedId === it.id }" | ||
| 10 | + @click="onSelect(it)" | ||
| 11 | + > | ||
| 12 | + <view class="card-row"> | ||
| 13 | + <text class="card-name">{{ safeText(it.name) }}</text> | ||
| 14 | + <text class="card-check" v-if="selectedId === it.id">✓</text> | ||
| 15 | + </view> | ||
| 16 | + <view class="card-row sub"> | ||
| 17 | + <text class="card-label">部门:</text> | ||
| 18 | + <text class="card-value">{{ safeText(it.deptName) }}</text> | ||
| 19 | + </view> | ||
| 20 | + <view class="card-row sub"> | ||
| 21 | + <text class="card-label">角色:</text> | ||
| 22 | + <text class="card-value">{{ safeText(it.roleName) }}</text> | ||
| 23 | + </view> | ||
| 24 | + <view class="card-row sub"> | ||
| 25 | + <text class="card-label">用户名:</text> | ||
| 26 | + <text class="card-value">{{ safeText(it.username) }}</text> | ||
| 27 | + </view> | ||
| 28 | + </view> | ||
| 29 | + </view> | ||
| 30 | + <view v-else-if="!loading" class="empty">暂无可分配人员</view> | ||
| 31 | + </scroll-view> | ||
| 32 | + | ||
| 33 | + <view class="footer"> | ||
| 34 | + <button class="btn submit" :disabled="!selectedId" @click="onSubmit">确定分配</button> | ||
| 35 | + </view> | ||
| 36 | + </view> | ||
| 37 | +</template> | ||
| 38 | + | ||
| 39 | +<script> | ||
| 40 | +import { supplierQuotationDealAssignUsersApi, supplierQuotationDealAssignApi } from '@/api/procure-manage/supplierQuotationDeal.js' | ||
| 41 | + | ||
| 42 | +export default { | ||
| 43 | + name: 'AssignQuoteManage', | ||
| 44 | + data() { | ||
| 45 | + return { | ||
| 46 | + id: '', | ||
| 47 | + purchaseDepartment: '', | ||
| 48 | + loading: false, | ||
| 49 | + users: [], | ||
| 50 | + selectedId: '' | ||
| 51 | + } | ||
| 52 | + }, | ||
| 53 | + onLoad(options) { | ||
| 54 | + this.id = (options && options.id) ? options.id : '' | ||
| 55 | + this.purchaseDepartment = (options && options.purchaseDepartment) ? options.purchaseDepartment : '' | ||
| 56 | + if (!this.id) { | ||
| 57 | + uni.showToast({ title: '缺少主键ID', icon: 'none' }) | ||
| 58 | + return | ||
| 59 | + } | ||
| 60 | + this.loadUsers() | ||
| 61 | + }, | ||
| 62 | + methods: { | ||
| 63 | + safeText(v) { | ||
| 64 | + const s = v == null ? '' : String(v) | ||
| 65 | + return s.trim() ? s : '-' | ||
| 66 | + }, | ||
| 67 | + async loadUsers() { | ||
| 68 | + this.loading = true | ||
| 69 | + try { | ||
| 70 | + const res = await supplierQuotationDealAssignUsersApi({ purchaseDepartment: this.purchaseDepartment }) | ||
| 71 | + const data = (res && res.data) ? res.data : [] | ||
| 72 | + this.users = Array.isArray(data) ? data : [] | ||
| 73 | + } catch (e) { | ||
| 74 | + this.users = [] | ||
| 75 | + uni.showToast({ title: '加载人员失败', icon: 'none' }) | ||
| 76 | + } finally { | ||
| 77 | + this.loading = false | ||
| 78 | + } | ||
| 79 | + }, | ||
| 80 | + onSelect(it) { | ||
| 81 | + this.selectedId = it.id | ||
| 82 | + }, | ||
| 83 | + async onSubmit() { | ||
| 84 | + if (!this.selectedId) { | ||
| 85 | + uni.showToast({ title: '请选择负责人', icon: 'none' }) | ||
| 86 | + return | ||
| 87 | + } | ||
| 88 | + const confirmRes = await new Promise(resolve => { | ||
| 89 | + uni.showModal({ title: '提示', content: '确定分配给该负责人吗?', confirmText: '确定', cancelText: '取消', success: resolve }) | ||
| 90 | + }) | ||
| 91 | + if (!(confirmRes && confirmRes.confirm)) return | ||
| 92 | + try { | ||
| 93 | + await supplierQuotationDealAssignApi({ id: this.id, principalId: this.selectedId }) | ||
| 94 | + uni.showToast({ title: '分配成功', icon: 'none' }) | ||
| 95 | + try { uni.setStorageSync('QUOTE_MANAGE_LIST_NEED_REFRESH', '1') } catch (e) {} | ||
| 96 | + setTimeout(() => { uni.navigateBack() }, 400) | ||
| 97 | + } catch (e) { | ||
| 98 | + uni.showToast({ title: e.msg || '分配失败', icon: 'none' }) | ||
| 99 | + } | ||
| 100 | + } | ||
| 101 | + } | ||
| 102 | +} | ||
| 103 | +</script> | ||
| 104 | + | ||
| 105 | +<style lang="scss" scoped> | ||
| 106 | +.page { | ||
| 107 | + display: flex; | ||
| 108 | + flex-direction: column; | ||
| 109 | + height: 100%; | ||
| 110 | + background: #f3f3f3; | ||
| 111 | +} | ||
| 112 | + | ||
| 113 | +.scroll { | ||
| 114 | + flex: 1; | ||
| 115 | + padding: 20rpx 0 200rpx; | ||
| 116 | +} | ||
| 117 | + | ||
| 118 | +.section { | ||
| 119 | + padding: 0 24rpx; | ||
| 120 | +} | ||
| 121 | + | ||
| 122 | +.card { | ||
| 123 | + background: #fff; | ||
| 124 | + border-radius: 12rpx; | ||
| 125 | + padding: 28rpx 32rpx; | ||
| 126 | + margin-bottom: 20rpx; | ||
| 127 | + border: 2rpx solid transparent; | ||
| 128 | + | ||
| 129 | + &.is-selected { | ||
| 130 | + border-color: $theme-primary; | ||
| 131 | + background: rgba($theme-primary, 0.04); | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + .card-row { | ||
| 135 | + display: flex; | ||
| 136 | + align-items: center; | ||
| 137 | + margin-bottom: 12rpx; | ||
| 138 | + | ||
| 139 | + &.sub { | ||
| 140 | + margin-bottom: 8rpx; | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + &:last-child { | ||
| 144 | + margin-bottom: 0; | ||
| 145 | + } | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + .card-name { | ||
| 149 | + flex: 1; | ||
| 150 | + font-size: 32rpx; | ||
| 151 | + font-weight: 600; | ||
| 152 | + color: rgba(0, 0, 0, 0.9); | ||
| 153 | + } | ||
| 154 | + | ||
| 155 | + .card-check { | ||
| 156 | + color: $theme-primary; | ||
| 157 | + font-size: 36rpx; | ||
| 158 | + font-weight: 700; | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + .card-label { | ||
| 162 | + font-size: 28rpx; | ||
| 163 | + color: rgba(0, 0, 0, 0.6); | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + .card-value { | ||
| 167 | + flex: 1; | ||
| 168 | + font-size: 28rpx; | ||
| 169 | + color: rgba(0, 0, 0, 0.9); | ||
| 170 | + } | ||
| 171 | +} | ||
| 172 | + | ||
| 173 | +.empty { | ||
| 174 | + text-align: center; | ||
| 175 | + color: rgba(0, 0, 0, 0.4); | ||
| 176 | + font-size: 28rpx; | ||
| 177 | + padding: 120rpx 0; | ||
| 178 | +} | ||
| 179 | + | ||
| 180 | +.footer { | ||
| 181 | + z-index: 2; | ||
| 182 | + position: fixed; | ||
| 183 | + left: 0; | ||
| 184 | + right: 0; | ||
| 185 | + bottom: 0; | ||
| 186 | + padding: 32rpx; | ||
| 187 | + padding-bottom: calc(32rpx + env(safe-area-inset-bottom)); | ||
| 188 | + background: #fff; | ||
| 189 | + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06); | ||
| 190 | + | ||
| 191 | + .btn { | ||
| 192 | + height: 80rpx; | ||
| 193 | + line-height: 80rpx; | ||
| 194 | + border-radius: 12rpx; | ||
| 195 | + font-size: 32rpx; | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + .submit { | ||
| 199 | + background: $theme-primary; | ||
| 200 | + color: #fff; | ||
| 201 | + | ||
| 202 | + &[disabled] { | ||
| 203 | + opacity: 0.5; | ||
| 204 | + } | ||
| 205 | + } | ||
| 206 | +} | ||
| 207 | +</style> |
pages/quote-manage/detail.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="page"> | ||
| 3 | + <scroll-view class="scroll" scroll-y> | ||
| 4 | + <view class="detail-page"> | ||
| 5 | + <view class="section"> | ||
| 6 | + <text class="row company">{{ safeText(form.projectName) }}</text> | ||
| 7 | + <view class="row"><text class="label">项目编号</text><text class="value">{{ safeText(form.projectCode) }}</text></view> | ||
| 8 | + <view class="row"><text class="label">报价时间</text><text class="value">{{ formatDateTimeMinute(form.quoteTime) }}</text></view> | ||
| 9 | + <view class="row"><text class="label">供应商名称</text><text class="value">{{ safeText(form.supplierName) }}</text></view> | ||
| 10 | + <view class="row"><text class="label">品种</text><text class="value">{{ safeText(form.productName) }}</text></view> | ||
| 11 | + <view class="row"><text class="label">数量</text><text class="value">{{ safeText(form.quantity) }}</text></view> | ||
| 12 | + <view class="row"><text class="label">价格</text><text class="value">{{ safeText(form.price) }}</text></view> | ||
| 13 | + <view class="row"><text class="label">采购处</text><text class="value">{{ safeText(form.purchaseDepartmentName) }}</text></view> | ||
| 14 | + <view class="row"><text class="label">负责人</text><text class="value">{{ safeText(form.principalName) }}</text></view> | ||
| 15 | + <view class="row"><text class="label">分配时间</text><text class="value">{{ formatDateTimeMinute(form.assignTime) }}</text></view> | ||
| 16 | + </view> | ||
| 17 | + </view> | ||
| 18 | + </scroll-view> | ||
| 19 | + | ||
| 20 | + <detail-buttons :buttons="displayButtons" @click="handleButtonClick" /> | ||
| 21 | + </view> | ||
| 22 | +</template> | ||
| 23 | + | ||
| 24 | +<script> | ||
| 25 | +import DetailButtons from '@/components/detail-buttons/index.vue' | ||
| 26 | +import { supplierQuotationDealGetApi } from '@/api/procure-manage/supplierQuotationDeal.js' | ||
| 27 | + | ||
| 28 | +export default { | ||
| 29 | + name: 'QuoteManageDetail', | ||
| 30 | + components: { DetailButtons }, | ||
| 31 | + data() { | ||
| 32 | + return { | ||
| 33 | + id: '', | ||
| 34 | + loading: false, | ||
| 35 | + form: {}, | ||
| 36 | + buttons: [{ | ||
| 37 | + text: '分配', | ||
| 38 | + visible: true, | ||
| 39 | + variant: 'primary', | ||
| 40 | + event: 'assign' | ||
| 41 | + }] | ||
| 42 | + } | ||
| 43 | + }, | ||
| 44 | + computed: { | ||
| 45 | + displayButtons() { | ||
| 46 | + return [ | ||
| 47 | + { ...this.buttons[0], visible: !this.form.principalId && this.$auth.hasPermi('procure-manage:quote-manage:assign') } | ||
| 48 | + ] | ||
| 49 | + } | ||
| 50 | + }, | ||
| 51 | + onShow() { | ||
| 52 | + const options = (this.$route && this.$route.query) ? this.$route.query : {} | ||
| 53 | + const id = options && options.id ? String(options.id) : '' | ||
| 54 | + this.id = id | ||
| 55 | + this.loadDetail() | ||
| 56 | + }, | ||
| 57 | + methods: { | ||
| 58 | + safeText(v) { | ||
| 59 | + const s = v == null ? '' : String(v) | ||
| 60 | + return s.trim() ? s : '-' | ||
| 61 | + }, | ||
| 62 | + formatDateTimeMinute(v) { | ||
| 63 | + const s = v == null ? '' : String(v).trim() | ||
| 64 | + if (!s) return '-' | ||
| 65 | + if (s.length >= 16) return s.slice(0, 16) | ||
| 66 | + if (s.length >= 10) return s.slice(0, 10) | ||
| 67 | + return s | ||
| 68 | + }, | ||
| 69 | + async loadDetail() { | ||
| 70 | + this.loading = true | ||
| 71 | + try { | ||
| 72 | + const res = await supplierQuotationDealGetApi(this.id) | ||
| 73 | + const data = (res && res.data) ? res.data : {} | ||
| 74 | + this.form = data | ||
| 75 | + } catch (e) { | ||
| 76 | + this.form = {} | ||
| 77 | + uni.showToast({ title: '详情加载失败', icon: 'none' }) | ||
| 78 | + } finally { | ||
| 79 | + this.loading = false | ||
| 80 | + } | ||
| 81 | + }, | ||
| 82 | + handleButtonClick(btn) { | ||
| 83 | + if (!btn || btn.disabled) return | ||
| 84 | + const e = btn.event || '' | ||
| 85 | + if (e === 'assign') return this.onAssign() | ||
| 86 | + }, | ||
| 87 | + onAssign() { | ||
| 88 | + const pd = this.form.purchaseDepartment || this.form.purchaseDepartmentId || '' | ||
| 89 | + uni.navigateTo({ url: '/pages/quote-manage/assign?id=' + this.id + '&purchaseDepartment=' + pd }) | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | +} | ||
| 93 | +</script> | ||
| 94 | + | ||
| 95 | +<style lang="scss" scoped> | ||
| 96 | +.page { | ||
| 97 | + display: flex; | ||
| 98 | + flex-direction: column; | ||
| 99 | + height: 100%; | ||
| 100 | +} | ||
| 101 | + | ||
| 102 | +.scroll { | ||
| 103 | + flex: 1; | ||
| 104 | + padding: 8rpx 0 144rpx; | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +.detail-page { | ||
| 108 | + background: #f3f3f3; | ||
| 109 | +} | ||
| 110 | + | ||
| 111 | +.section { | ||
| 112 | + padding: 32rpx; | ||
| 113 | + background: #fff; | ||
| 114 | + margin-bottom: 20rpx; | ||
| 115 | +} | ||
| 116 | + | ||
| 117 | +.row { | ||
| 118 | + display: flex; | ||
| 119 | + margin-bottom: 28rpx; | ||
| 120 | + | ||
| 121 | + &:last-child { | ||
| 122 | + margin-bottom: 0; | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + &.company { | ||
| 126 | + font-size: 36rpx; | ||
| 127 | + font-weight: 600; | ||
| 128 | + color: rgba(0, 0, 0, 0.9); | ||
| 129 | + padding-top: 8rpx; | ||
| 130 | + line-height: 50rpx; | ||
| 131 | + margin-bottom: 32rpx; | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + .label { | ||
| 135 | + max-width: 420rpx; | ||
| 136 | + margin-right: 20rpx; | ||
| 137 | + line-height: 32rpx; | ||
| 138 | + font-size: 28rpx; | ||
| 139 | + color: rgba(0, 0, 0, 0.6); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + .value { | ||
| 143 | + flex: 1; | ||
| 144 | + line-height: 32rpx; | ||
| 145 | + font-size: 28rpx; | ||
| 146 | + color: rgba(0, 0, 0, 0.9); | ||
| 147 | + text-align: right; | ||
| 148 | + word-break: break-all; | ||
| 149 | + } | ||
| 150 | +} | ||
| 151 | +</style> |
pages/quote-manage/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="page"> | ||
| 3 | + <view class="dev-list-fixed"> | ||
| 4 | + <view class="search-row"> | ||
| 5 | + <uni-search-bar v-model="searchKeyword" radius="6" placeholder="请输入项目名称" clearButton="auto" | ||
| 6 | + cancelButton="none" bgColor="#F3F3F3" textColor="rgba(0,0,0,0.4)" @confirm="search" | ||
| 7 | + @input="onSearchInput" /> | ||
| 8 | + <view class="tool-icons"> | ||
| 9 | + <image class="tool-icon" src="/static/images/dev_manage/filter_icon.png" @click="openFilter" /> | ||
| 10 | + </view> | ||
| 11 | + </view> | ||
| 12 | + </view> | ||
| 13 | + | ||
| 14 | + <view class="list-box"> | ||
| 15 | + <card-list ref="cardRef" :fetch-fn="fetchList" :query="query" :extra="extraParams" row-key="id" | ||
| 16 | + :enable-refresh="true" :enable-load-more="true" @loaded="onCardLoaded" @error="onCardError"> | ||
| 17 | + <template v-slot="{ item }"> | ||
| 18 | + <view class="card" @click.stop="onCardClick(item)"> | ||
| 19 | + <view class="card-header"> | ||
| 20 | + <text class="title omit2">{{ item.projectName || '-' }}</text> | ||
| 21 | + </view> | ||
| 22 | + <view class="info-row"> | ||
| 23 | + <text>项目编号</text><text>{{ item.projectCode || '-' }}</text> | ||
| 24 | + </view> | ||
| 25 | + <view class="info-row"> | ||
| 26 | + <text>品种</text><text>{{ item.productName || '-' }}</text> | ||
| 27 | + </view> | ||
| 28 | + <view class="info-row"> | ||
| 29 | + <text>供应商名称</text><text>{{ item.supplierName || '-' }}</text> | ||
| 30 | + </view> | ||
| 31 | + <view class="info-row"> | ||
| 32 | + <text>价格</text><text>{{ item.price != null ? item.price : '-' }}</text> | ||
| 33 | + </view> | ||
| 34 | + </view> | ||
| 35 | + </template> | ||
| 36 | + </card-list> | ||
| 37 | + </view> | ||
| 38 | + | ||
| 39 | + <filter-modal :visible.sync="filterVisible" :value.sync="filterForm" title="筛选" @reset="onFilterReset" | ||
| 40 | + @confirm="onFilterConfirm"> | ||
| 41 | + <template v-slot="{ model }"> | ||
| 42 | + <view class="filter-form"> | ||
| 43 | + <view class="form-item"> | ||
| 44 | + <view class="label">项目编号</view> | ||
| 45 | + <uni-easyinput v-model="model.projectCode" placeholder="请输入项目编号" :inputBorder="true" /> | ||
| 46 | + </view> | ||
| 47 | + <view class="form-item"> | ||
| 48 | + <view class="label">供应商名称</view> | ||
| 49 | + <uni-easyinput v-model="model.supplierName" placeholder="请输入供应商名称" :inputBorder="true" /> | ||
| 50 | + </view> | ||
| 51 | + </view> | ||
| 52 | + </template> | ||
| 53 | + </filter-modal> | ||
| 54 | + </view> | ||
| 55 | +</template> | ||
| 56 | + | ||
| 57 | +<script> | ||
| 58 | +import CardList from '@/components/card/index.vue' | ||
| 59 | +import FilterModal from '@/components/filter/index.vue' | ||
| 60 | +import { supplierQuotationDealQueryApi } from '@/api/procure-manage/supplierQuotationDeal.js' | ||
| 61 | + | ||
| 62 | +export default { | ||
| 63 | + name: 'QuoteManageList', | ||
| 64 | + components: { CardList, FilterModal }, | ||
| 65 | + data() { | ||
| 66 | + return { | ||
| 67 | + searchKeyword: '', | ||
| 68 | + searchKeywordDebounced: '', | ||
| 69 | + searchDebounceTimer: null, | ||
| 70 | + query: { | ||
| 71 | + projectName: '', | ||
| 72 | + projectCode: '', | ||
| 73 | + supplierName: '' | ||
| 74 | + }, | ||
| 75 | + extraParams: {}, | ||
| 76 | + currentItems: [], | ||
| 77 | + filterVisible: false, | ||
| 78 | + filterForm: { | ||
| 79 | + projectCode: '', | ||
| 80 | + supplierName: '' | ||
| 81 | + } | ||
| 82 | + } | ||
| 83 | + }, | ||
| 84 | + watch: { | ||
| 85 | + searchKeywordDebounced(v) { | ||
| 86 | + this.query = { ...this.query, projectName: v || '' } | ||
| 87 | + } | ||
| 88 | + }, | ||
| 89 | + onShow() { | ||
| 90 | + let needRefresh = '' | ||
| 91 | + try { needRefresh = uni.getStorageSync('QUOTE_MANAGE_LIST_NEED_REFRESH') } catch (e) {} | ||
| 92 | + if (!needRefresh) return | ||
| 93 | + try { uni.removeStorageSync('QUOTE_MANAGE_LIST_NEED_REFRESH') } catch (e) {} | ||
| 94 | + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.reload) { | ||
| 95 | + this.$refs.cardRef.reload() | ||
| 96 | + } | ||
| 97 | + }, | ||
| 98 | + onReachBottom() { | ||
| 99 | + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) { | ||
| 100 | + this.$refs.cardRef.onLoadMore() | ||
| 101 | + } | ||
| 102 | + }, | ||
| 103 | + beforeDestroy() { | ||
| 104 | + if (this.searchDebounceTimer) { | ||
| 105 | + clearTimeout(this.searchDebounceTimer) | ||
| 106 | + this.searchDebounceTimer = null | ||
| 107 | + } | ||
| 108 | + }, | ||
| 109 | + methods: { | ||
| 110 | + onCardLoaded({ items }) { | ||
| 111 | + this.currentItems = items | ||
| 112 | + }, | ||
| 113 | + onCardError() { | ||
| 114 | + uni.showToast({ title: '列表加载失败', icon: 'none' }) | ||
| 115 | + }, | ||
| 116 | + onSearchInput() { | ||
| 117 | + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer) | ||
| 118 | + this.searchDebounceTimer = setTimeout(() => { | ||
| 119 | + this.searchKeywordDebounced = this.searchKeyword | ||
| 120 | + this.searchDebounceTimer = null | ||
| 121 | + }, 1200) | ||
| 122 | + }, | ||
| 123 | + search(e) { | ||
| 124 | + const val = e && e.value != null ? e.value : this.searchKeyword | ||
| 125 | + this.searchKeyword = val | ||
| 126 | + this.searchKeywordDebounced = val | ||
| 127 | + }, | ||
| 128 | + openFilter() { | ||
| 129 | + this.filterForm = { | ||
| 130 | + projectCode: this.query.projectCode || '', | ||
| 131 | + supplierName: this.query.supplierName || '' | ||
| 132 | + } | ||
| 133 | + this.filterVisible = true | ||
| 134 | + }, | ||
| 135 | + onFilterReset(payload) { | ||
| 136 | + this.filterForm = payload | ||
| 137 | + }, | ||
| 138 | + onFilterConfirm(payload) { | ||
| 139 | + this.query = { | ||
| 140 | + projectName: this.query.projectName || '', | ||
| 141 | + projectCode: payload.projectCode || '', | ||
| 142 | + supplierName: payload.supplierName || '' | ||
| 143 | + } | ||
| 144 | + }, | ||
| 145 | + onCardClick(item) { | ||
| 146 | + uni.navigateTo({ url: '/pages/quote-manage/detail?id=' + item.id }) | ||
| 147 | + }, | ||
| 148 | + fetchList({ pageIndex, pageSize, query }) { | ||
| 149 | + const q = query || {} | ||
| 150 | + const params = { | ||
| 151 | + pageIndex, | ||
| 152 | + pageSize, | ||
| 153 | + projectName: q.projectName || '', | ||
| 154 | + projectCode: q.projectCode || '', | ||
| 155 | + supplierName: q.supplierName || '' | ||
| 156 | + } | ||
| 157 | + return supplierQuotationDealQueryApi(params).then(res => { | ||
| 158 | + const _data = res && res.data ? res.data : {} | ||
| 159 | + let records = _data.datas || _data.list || _data.records || [] | ||
| 160 | + const totalCount = _data.totalCount || _data.count || 0 | ||
| 161 | + const hasNext = _data.hasNext || false | ||
| 162 | + records = records.map(it => ({ ...it })) | ||
| 163 | + return { records, totalCount, hasNext } | ||
| 164 | + }).catch(() => { | ||
| 165 | + this.onCardError() | ||
| 166 | + return { records: [], totalCount: 0, hasNext: false } | ||
| 167 | + }) | ||
| 168 | + } | ||
| 169 | + } | ||
| 170 | +} | ||
| 171 | +</script> | ||
| 172 | + | ||
| 173 | +<style lang="scss" scoped> | ||
| 174 | +.page { | ||
| 175 | + display: flex; | ||
| 176 | + flex-direction: column; | ||
| 177 | + height: 100vh; | ||
| 178 | +} | ||
| 179 | + | ||
| 180 | +.dev-list-fixed { | ||
| 181 | + position: fixed; | ||
| 182 | + top: 96rpx; | ||
| 183 | + left: 0; | ||
| 184 | + right: 0; | ||
| 185 | + z-index: 2; | ||
| 186 | + background: #fff; | ||
| 187 | + | ||
| 188 | + .search-row { | ||
| 189 | + display: flex; | ||
| 190 | + align-items: center; | ||
| 191 | + padding: 16rpx 32rpx; | ||
| 192 | + | ||
| 193 | + .uni-searchbar { | ||
| 194 | + padding: 0; | ||
| 195 | + flex: 1; | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + .tool-icons { | ||
| 199 | + display: flex; | ||
| 200 | + | ||
| 201 | + .tool-icon { | ||
| 202 | + width: 48rpx; | ||
| 203 | + height: 48rpx; | ||
| 204 | + display: block; | ||
| 205 | + margin-left: 32rpx; | ||
| 206 | + } | ||
| 207 | + } | ||
| 208 | + } | ||
| 209 | +} | ||
| 210 | + | ||
| 211 | +::v-deep .uni-searchbar__box { | ||
| 212 | + height: 80rpx !important; | ||
| 213 | + justify-content: start; | ||
| 214 | + | ||
| 215 | + .uni-searchbar__box-search-input { | ||
| 216 | + font-size: 32rpx !important; | ||
| 217 | + } | ||
| 218 | +} | ||
| 219 | + | ||
| 220 | +.list-box { | ||
| 221 | + flex: 1; | ||
| 222 | + padding-top: 140rpx; | ||
| 223 | + | ||
| 224 | + .card { | ||
| 225 | + position: relative; | ||
| 226 | + } | ||
| 227 | + | ||
| 228 | + .card-header { | ||
| 229 | + margin-bottom: 28rpx; | ||
| 230 | + position: relative; | ||
| 231 | + | ||
| 232 | + .title { | ||
| 233 | + font-size: 36rpx; | ||
| 234 | + font-weight: 600; | ||
| 235 | + line-height: 50rpx; | ||
| 236 | + color: rgba(0, 0, 0, 0.9); | ||
| 237 | + width: 578rpx; | ||
| 238 | + } | ||
| 239 | + } | ||
| 240 | + | ||
| 241 | + .info-row { | ||
| 242 | + display: flex; | ||
| 243 | + align-items: center; | ||
| 244 | + color: rgba(0, 0, 0, 0.6); | ||
| 245 | + font-size: 28rpx; | ||
| 246 | + margin-bottom: 24rpx; | ||
| 247 | + height: 32rpx; | ||
| 248 | + | ||
| 249 | + &:last-child { | ||
| 250 | + margin-bottom: 0; | ||
| 251 | + } | ||
| 252 | + | ||
| 253 | + text { | ||
| 254 | + width: 50%; | ||
| 255 | + | ||
| 256 | + &:last-child { | ||
| 257 | + color: rgba(0, 0, 0, 0.9); | ||
| 258 | + width: 50%; | ||
| 259 | + } | ||
| 260 | + } | ||
| 261 | + } | ||
| 262 | +} | ||
| 263 | + | ||
| 264 | +.filter-form { | ||
| 265 | + .form-item { | ||
| 266 | + margin-bottom: 24rpx; | ||
| 267 | + } | ||
| 268 | + | ||
| 269 | + .label { | ||
| 270 | + margin-bottom: 20rpx; | ||
| 271 | + color: rgba(0, 0, 0, 0.9); | ||
| 272 | + height: 44rpx; | ||
| 273 | + line-height: 44rpx; | ||
| 274 | + font-size: 30rpx; | ||
| 275 | + } | ||
| 276 | +} | ||
| 277 | +</style> |
pages/sales-price/add.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="page"> | ||
| 3 | + <scroll-view class="scroll" scroll-y> | ||
| 4 | + <uni-list> | ||
| 5 | + <!-- 编号 --> | ||
| 6 | + <uni-list-item class="select-item" :class="form.code ? 'is-filled' : 'is-empty'"> | ||
| 7 | + <template v-slot:body> | ||
| 8 | + <view class="item-title"><text class="required">*</text><text>编号</text></view> | ||
| 9 | + </template> | ||
| 10 | + <template v-slot:footer> | ||
| 11 | + <view class="serial-number-row"> | ||
| 12 | + <text class="readonly-text value-code">{{ form.code }}</text> | ||
| 13 | + <button class="generate-btn" @click="initCode">点此生成</button> | ||
| 14 | + </view> | ||
| 15 | + </template> | ||
| 16 | + </uni-list-item> | ||
| 17 | + | ||
| 18 | + <!-- 供应商名称 --> | ||
| 19 | + <uni-list-item class="select-item" :class="form.supplierId ? 'is-filled' : 'is-empty'" clickable | ||
| 20 | + @click="openSupplierSheet" :rightText="form.supplierName || '请选择供应商名称'" showArrow> | ||
| 21 | + <template v-slot:body> | ||
| 22 | + <view class="item-title"><text class="required">*</text><text>供应商名称</text></view> | ||
| 23 | + </template> | ||
| 24 | + </uni-list-item> | ||
| 25 | + | ||
| 26 | + <!-- 采购处(带出,禁用) --> | ||
| 27 | + <uni-list-item title="采购处"> | ||
| 28 | + <template v-slot:footer> | ||
| 29 | + <uni-easyinput v-model="form.purchaseDepartmentName" :inputBorder="false" disabled placeholder="选择供应商后自动带出" /> | ||
| 30 | + </template> | ||
| 31 | + </uni-list-item> | ||
| 32 | + | ||
| 33 | + <!-- 区域(带出,禁用) --> | ||
| 34 | + <uni-list-item title="区域"> | ||
| 35 | + <template v-slot:footer> | ||
| 36 | + <uni-easyinput v-model="form.regionName" :inputBorder="false" disabled placeholder="选择供应商后自动带出" /> | ||
| 37 | + </template> | ||
| 38 | + </uni-list-item> | ||
| 39 | + | ||
| 40 | + <!-- 报价时效 --> | ||
| 41 | + <uni-list-item> | ||
| 42 | + <template v-slot:body> | ||
| 43 | + <view class="item-title"><text class="required">*</text><text>报价时效</text></view> | ||
| 44 | + </template> | ||
| 45 | + <template v-slot:footer> | ||
| 46 | + <uni-easyinput v-model="form.validityPeriod" :inputBorder="false" placeholder="请输入报价时效" /> | ||
| 47 | + </template> | ||
| 48 | + </uni-list-item> | ||
| 49 | + | ||
| 50 | + <!-- 报价人(当前登录用户,禁用) --> | ||
| 51 | + <uni-list-item title="报价人"> | ||
| 52 | + <template v-slot:footer> | ||
| 53 | + <uni-easyinput v-model="form.quoterName" :inputBorder="false" disabled placeholder="自动获取" /> | ||
| 54 | + </template> | ||
| 55 | + </uni-list-item> | ||
| 56 | + | ||
| 57 | + <!-- 是否长单操作 --> | ||
| 58 | + <uni-list-item class="select-item" :class="typeof form.longTermOperation === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 59 | + @click="openSheet('longTermOperation')" :rightText="boolText(form.longTermOperation)" showArrow> | ||
| 60 | + <template v-slot:body> | ||
| 61 | + <view class="item-title"><text class="required">*</text><text>是否长单操作</text></view> | ||
| 62 | + </template> | ||
| 63 | + </uni-list-item> | ||
| 64 | + | ||
| 65 | + <!-- 是否终端客户 --> | ||
| 66 | + <uni-list-item class="select-item" :class="typeof form.terminalCustomer === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 67 | + @click="openSheet('terminalCustomer')" :rightText="boolText(form.terminalCustomer)" showArrow> | ||
| 68 | + <template v-slot:body> | ||
| 69 | + <view class="item-title"><text class="required">*</text><text>是否终端客户</text></view> | ||
| 70 | + </template> | ||
| 71 | + </uni-list-item> | ||
| 72 | + | ||
| 73 | + <!-- 是否未点价 --> | ||
| 74 | + <uni-list-item class="select-item" :class="typeof form.priced === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 75 | + @click="openSheet('priced')" :rightText="boolText(form.priced)" showArrow> | ||
| 76 | + <template v-slot:body> | ||
| 77 | + <view class="item-title"><text class="required">*</text><text>是否未点价</text></view> | ||
| 78 | + </template> | ||
| 79 | + </uni-list-item> | ||
| 80 | + | ||
| 81 | + <!-- 点价截止日期 - 仅在 是否未点价 = 是 时显示且必填 --> | ||
| 82 | + <uni-list-item v-if="form.priced === true" class="select-item" :class="form.pricingDeadline ? 'is-filled' : 'is-empty'"> | ||
| 83 | + <template v-slot:body> | ||
| 84 | + <view class="item-title"><text class="required">*</text><text>点价截止日期</text></view> | ||
| 85 | + </template> | ||
| 86 | + <template v-slot:footer> | ||
| 87 | + <uni-datetime-picker type="date" v-model="form.pricingDeadline" /> | ||
| 88 | + </template> | ||
| 89 | + </uni-list-item> | ||
| 90 | + | ||
| 91 | + <!-- 是否暂定价 - 仅在 是否未点价 = 是 时显示 --> | ||
| 92 | + <uni-list-item v-if="form.priced === true" class="select-item" :class="typeof form.temporaryPrice === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 93 | + @click="openSheet('temporaryPrice')" :rightText="boolText(form.temporaryPrice)" showArrow> | ||
| 94 | + <template v-slot:body> | ||
| 95 | + <view class="item-title"><text>是否暂定价</text></view> | ||
| 96 | + </template> | ||
| 97 | + </uni-list-item> | ||
| 98 | + | ||
| 99 | + <!-- 其他费用凭票到厂另行结算 --> | ||
| 100 | + <uni-list-item class="select-item" :class="typeof form.otherExpenseSettlement === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 101 | + @click="openSheet('otherExpenseSettlement')" :rightText="boolText(form.otherExpenseSettlement)" showArrow> | ||
| 102 | + <template v-slot:body> | ||
| 103 | + <view class="item-title"><text class="required">*</text><text>其他费用凭票到厂另行结算</text></view> | ||
| 104 | + </template> | ||
| 105 | + </uni-list-item> | ||
| 106 | + | ||
| 107 | + <!-- 交提货方式 --> | ||
| 108 | + <uni-list-item class="select-item" :class="form.deliveryMode ? 'is-filled' : 'is-empty'" clickable | ||
| 109 | + @click="openDictSheet('deliveryMode', 'DELIVERY_METHOD', '交提货方式')" :rightText="getDeliveryMethodLabel() || '请选择交提货方式'" showArrow> | ||
| 110 | + <template v-slot:body> | ||
| 111 | + <view class="item-title"><text class="required">*</text><text>交提货方式</text></view> | ||
| 112 | + </template> | ||
| 113 | + </uni-list-item> | ||
| 114 | + | ||
| 115 | + <!-- 是否通货买断 --> | ||
| 116 | + <uni-list-item class="select-item" :class="typeof form.commodityBuyout === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 117 | + @click="openSheet('commodityBuyout')" :rightText="boolText(form.commodityBuyout)" showArrow> | ||
| 118 | + <template v-slot:body> | ||
| 119 | + <view class="item-title"><text class="required">*</text><text>是否通货买断</text></view> | ||
| 120 | + </template> | ||
| 121 | + </uni-list-item> | ||
| 122 | + | ||
| 123 | + <!-- 是否质量买断 --> | ||
| 124 | + <uni-list-item class="select-item" :class="typeof form.qualityBuyout === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 125 | + @click="openSheet('qualityBuyout')" :rightText="boolText(form.qualityBuyout)" showArrow> | ||
| 126 | + <template v-slot:body> | ||
| 127 | + <view class="item-title"><text class="required">*</text><text>是否质量买断</text></view> | ||
| 128 | + </template> | ||
| 129 | + </uni-list-item> | ||
| 130 | + | ||
| 131 | + <!-- 是否数量买断 --> | ||
| 132 | + <uni-list-item class="select-item" :class="typeof form.quantityBuyout === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 133 | + @click="openSheet('quantityBuyout')" :rightText="boolText(form.quantityBuyout)" showArrow> | ||
| 134 | + <template v-slot:body> | ||
| 135 | + <view class="item-title"><text class="required">*</text><text>是否数量买断</text></view> | ||
| 136 | + </template> | ||
| 137 | + </uni-list-item> | ||
| 138 | + | ||
| 139 | + <!-- 是否送货上门 --> | ||
| 140 | + <uni-list-item class="select-item" :class="typeof form.doorDelivery === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 141 | + @click="openSheet('doorDelivery')" :rightText="boolText(form.doorDelivery)" showArrow> | ||
| 142 | + <template v-slot:body> | ||
| 143 | + <view class="item-title"><text class="required">*</text><text>是否送货上门</text></view> | ||
| 144 | + </template> | ||
| 145 | + </uni-list-item> | ||
| 146 | + | ||
| 147 | + <!-- 装车费 --> | ||
| 148 | + <uni-list-item title="装车费"> | ||
| 149 | + <template v-slot:footer> | ||
| 150 | + <uni-easyinput v-model="form.loadingFee" type="digit" :inputBorder="false" placeholder="请输入装车费" /> | ||
| 151 | + </template> | ||
| 152 | + </uni-list-item> | ||
| 153 | + | ||
| 154 | + <!-- 开票品种 --> | ||
| 155 | + <uni-list-item> | ||
| 156 | + <template v-slot:body> | ||
| 157 | + <view class="item-title"><text class="required">*</text><text>开票品种</text></view> | ||
| 158 | + </template> | ||
| 159 | + <template v-slot:footer> | ||
| 160 | + <uni-easyinput v-model="form.invoiceProductName" :inputBorder="false" placeholder="请输入开票品种" /> | ||
| 161 | + </template> | ||
| 162 | + </uni-list-item> | ||
| 163 | + | ||
| 164 | + <!-- 交货日期 --> | ||
| 165 | + <uni-list-item> | ||
| 166 | + <template v-slot:body> | ||
| 167 | + <view class="item-title"><text class="required">*</text><text>交货日期</text></view> | ||
| 168 | + </template> | ||
| 169 | + <template v-slot:footer> | ||
| 170 | + <uni-datetime-picker type="date" v-model="form.deliveryDate" /> | ||
| 171 | + </template> | ||
| 172 | + </uni-list-item> | ||
| 173 | + | ||
| 174 | + <!-- 结算方式 --> | ||
| 175 | + <uni-list-item> | ||
| 176 | + <template v-slot:body> | ||
| 177 | + <view class="item-title"><text class="required">*</text><text>结算方式</text></view> | ||
| 178 | + </template> | ||
| 179 | + <template v-slot:footer> | ||
| 180 | + <uni-easyinput v-model="form.settlementMethod" :inputBorder="false" placeholder="请输入结算方式" /> | ||
| 181 | + </template> | ||
| 182 | + </uni-list-item> | ||
| 183 | + | ||
| 184 | + <!-- 结算比例(%) --> | ||
| 185 | + <uni-list-item> | ||
| 186 | + <template v-slot:body> | ||
| 187 | + <view class="item-title"><text class="required">*</text><text>结算比例(%)</text></view> | ||
| 188 | + </template> | ||
| 189 | + <template v-slot:footer> | ||
| 190 | + <uni-easyinput v-model="form.settlementRatio" type="digit" :inputBorder="false" placeholder="请输入结算比例" @blur="onRatioBlur" /> | ||
| 191 | + </template> | ||
| 192 | + </uni-list-item> | ||
| 193 | + | ||
| 194 | + <!-- 协调事由 --> | ||
| 195 | + <uni-list-item title="协调事由"> | ||
| 196 | + <template v-slot:footer> | ||
| 197 | + <uni-easyinput v-model="form.coordinationReason" :inputBorder="false" placeholder="请输入协调事由" disabled /> | ||
| 198 | + </template> | ||
| 199 | + </uni-list-item> | ||
| 200 | + | ||
| 201 | + <!-- 票类状况 --> | ||
| 202 | + <uni-list-item title="票类状况"> | ||
| 203 | + <template v-slot:footer> | ||
| 204 | + <uni-easyinput v-model="form.invoiceTypeStatus" :inputBorder="false" placeholder="请输入票类状况" disabled /> | ||
| 205 | + </template> | ||
| 206 | + </uni-list-item> | ||
| 207 | + | ||
| 208 | + <!-- 明细信息 --> | ||
| 209 | + <ProductRel ref="productRel" mode="add" :options="productList" :priced="form.priced" @change="onProductsChange" /> | ||
| 210 | + </uni-list> | ||
| 211 | + | ||
| 212 | + <!-- 料质状况模块(明细下方) --> | ||
| 213 | + <view class="material-condition-section"> | ||
| 214 | + <view class="section-header"> | ||
| 215 | + <image class="opCollapse" src="/static/images/title.png" /> | ||
| 216 | + <text class="section-title">料质状况</text> | ||
| 217 | + </view> | ||
| 218 | + <view class="section-content"> | ||
| 219 | + <view class="form-row"> | ||
| 220 | + <text class="form-label">是否启用料质状况</text> | ||
| 221 | + <view class="bool-btns"> | ||
| 222 | + <view class="bool-btn" :class="{ active: form.materialConditionEnabled === true }" @click="form.materialConditionEnabled = true">是</view> | ||
| 223 | + <view class="bool-btn" :class="{ active: form.materialConditionEnabled === false }" @click="form.materialConditionEnabled = false">否</view> | ||
| 224 | + </view> | ||
| 225 | + </view> | ||
| 226 | + | ||
| 227 | + <template v-if="form.materialConditionEnabled"> | ||
| 228 | + <view v-for="mc in materialConditionConfigs" :key="mc.field" class="material-group"> | ||
| 229 | + <text class="material-label">{{ mc.label }}</text> | ||
| 230 | + <view class="tag-list"> | ||
| 231 | + <view | ||
| 232 | + v-for="opt in getDictOptions(mc.dictCode)" | ||
| 233 | + :key="opt.code" | ||
| 234 | + class="tag-btn" | ||
| 235 | + :class="{ active: isTagSelected(mc.field, opt.code) }" | ||
| 236 | + @click="toggleTag(mc.field, opt.code)" | ||
| 237 | + > | ||
| 238 | + {{ opt.name }} | ||
| 239 | + </view> | ||
| 240 | + </view> | ||
| 241 | + </view> | ||
| 242 | + </template> | ||
| 243 | + </view> | ||
| 244 | + </view> | ||
| 245 | + | ||
| 246 | + <!-- 备注模块 --> | ||
| 247 | + <view class="remark-section"> | ||
| 248 | + <view class="section-header"> | ||
| 249 | + <image class="opCollapse" src="/static/images/title.png" /> | ||
| 250 | + <text class="section-title">备注</text> | ||
| 251 | + </view> | ||
| 252 | + <view class="section-content"> | ||
| 253 | + <uni-easyinput v-model="form.remark" type="textarea" :inputBorder="false" placeholder="请输入备注" maxlength="2000" /> | ||
| 254 | + </view> | ||
| 255 | + </view> | ||
| 256 | + | ||
| 257 | + <view class="footer"> | ||
| 258 | + <button class="btn submit" type="primary" @click="onSubmit">提交</button> | ||
| 259 | + </view> | ||
| 260 | + </scroll-view> | ||
| 261 | + | ||
| 262 | + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" | ||
| 263 | + v-model="sheet.value" @confirm="onSheetConfirm" /> | ||
| 264 | + | ||
| 265 | + <RelateSelectSheet :visible.sync="supplierSheet.visible" :title="supplierSheet.title" | ||
| 266 | + :fetchFn="supplierSheet.fetchFn" :display-fields="supplierSheet.displayFields" | ||
| 267 | + :multiple="false" row-key="id" :selectedKeys.sync="supplierSheet.selectedKeys" | ||
| 268 | + @confirm="onSupplierConfirm" /> | ||
| 269 | + </view> | ||
| 270 | +</template> | ||
| 271 | +<script> | ||
| 272 | +import SingleSelectSheet from '@/components/single-select/index.vue' | ||
| 273 | +import RelateSelectSheet from '@/components/relate-select/index.vue' | ||
| 274 | +import ProductRel from './productRel.vue' | ||
| 275 | +import { salesmanQuotationGenerateCodeApi, salesmanQuotationSaveApi, breedRelationshipQueryApi } from '@/api/procure-manage/salesmanQuotation.js' | ||
| 276 | +import { domesticCustomerCreditQueryApi } from '@/api/procure-manage/domesticCustomerCredit.js' | ||
| 277 | +import { getInfo } from '@/api/login.js' | ||
| 278 | +import { getDicByCodes } from '@/utils/dic.js' | ||
| 279 | + | ||
| 280 | +export default { | ||
| 281 | + name: 'AddSalesPrice', | ||
| 282 | + components: { SingleSelectSheet, RelateSelectSheet, ProductRel }, | ||
| 283 | + data() { | ||
| 284 | + return { | ||
| 285 | + form: { | ||
| 286 | + code: '', | ||
| 287 | + supplierId: '', | ||
| 288 | + supplierName: '', | ||
| 289 | + purchaseDepartmentName: '', | ||
| 290 | + regionName: '', | ||
| 291 | + validityPeriod: '', | ||
| 292 | + quoterName: '', | ||
| 293 | + longTermOperation: false, | ||
| 294 | + terminalCustomer: false, | ||
| 295 | + priced: true, | ||
| 296 | + pricingDeadline: '', | ||
| 297 | + temporaryPrice: null, | ||
| 298 | + otherExpenseSettlement: false, | ||
| 299 | + deliveryMode: '', | ||
| 300 | + commodityBuyout: false, | ||
| 301 | + qualityBuyout: false, | ||
| 302 | + quantityBuyout: false, | ||
| 303 | + doorDelivery: false, | ||
| 304 | + loadingFee: '', | ||
| 305 | + invoiceProductName: '', | ||
| 306 | + deliveryDate: '', | ||
| 307 | + settlementMethod: '', | ||
| 308 | + settlementRatio: '', | ||
| 309 | + coordinationReason: '受市场影响,申请协调协调事由', | ||
| 310 | + invoiceTypeStatus: '增票', | ||
| 311 | + materialConditionEnabled: false, | ||
| 312 | + materialConditionCopperRice: [], | ||
| 313 | + materialConditionBrightCopper: [], | ||
| 314 | + materialConditionFirstClass: [], | ||
| 315 | + materialConditionSecondClass: [], | ||
| 316 | + materialConditionTinCoated: [], | ||
| 317 | + materialConditionScrap: [], | ||
| 318 | + materialConditionWhiteYellow: [], | ||
| 319 | + materialConditionPhosphorCopper: [], | ||
| 320 | + remark: '' | ||
| 321 | + }, | ||
| 322 | + productList: [], | ||
| 323 | + productLineList: [], | ||
| 324 | + sheet: { visible: false, title: '请选择', options: [], value: '', field: '' }, | ||
| 325 | + supplierSheet: { | ||
| 326 | + visible: false, | ||
| 327 | + title: '选择供应商', | ||
| 328 | + fetchFn: null, | ||
| 329 | + displayFields: [ | ||
| 330 | + { label: '单位名称', field: 'unitName' }, | ||
| 331 | + { label: '采购处', field: 'purchaseDepartmentName' }, | ||
| 332 | + { label: '区域', field: 'regionName' } | ||
| 333 | + ], | ||
| 334 | + selectedKeys: [] | ||
| 335 | + }, | ||
| 336 | + materialConditionConfigs: [ | ||
| 337 | + { field: 'materialConditionCopperRice', label: '铜米', dictCode: 'COPPER_RICE' }, | ||
| 338 | + { field: 'materialConditionBrightCopper', label: '光亮铜', dictCode: 'BRIGHT_COPPER' }, | ||
| 339 | + { field: 'materialConditionFirstClass', label: '一特', dictCode: 'FIRST_CLASS' }, | ||
| 340 | + { field: 'materialConditionSecondClass', label: '二特', dictCode: 'SECOND_CLASS' }, | ||
| 341 | + { field: 'materialConditionTinCoated', label: '镀锡紫', dictCode: 'TIN_COATED' }, | ||
| 342 | + { field: 'materialConditionScrap', label: '角料', dictCode: 'SCRAP' }, | ||
| 343 | + { field: 'materialConditionWhiteYellow', label: '镀白黄', dictCode: 'WHITE_YELLOW' }, | ||
| 344 | + { field: 'materialConditionPhosphorCopper', label: '磷铜', dictCode: 'PHOSPHOR_COPPER' } | ||
| 345 | + ], | ||
| 346 | + dictData: {} | ||
| 347 | + } | ||
| 348 | + }, | ||
| 349 | + created() { | ||
| 350 | + this.supplierSheet.fetchFn = this.fetchSuppliers.bind(this) | ||
| 351 | + this.initCode() | ||
| 352 | + this.loadQuoter() | ||
| 353 | + this.loadProducts() | ||
| 354 | + this.loadDictData() | ||
| 355 | + }, | ||
| 356 | + methods: { | ||
| 357 | + async loadDictData() { | ||
| 358 | + try { | ||
| 359 | + const codes = [...this.materialConditionConfigs.map(mc => mc.dictCode), 'DELIVERY_METHOD'] | ||
| 360 | + const res = await getDicByCodes(codes) | ||
| 361 | + this.dictData = res || {} | ||
| 362 | + } catch (e) { | ||
| 363 | + this.dictData = {} | ||
| 364 | + } | ||
| 365 | + }, | ||
| 366 | + getDictOptions(dictCode) { | ||
| 367 | + const data = this.dictData[dictCode] | ||
| 368 | + return (data && data.data) ? data.data : [] | ||
| 369 | + }, | ||
| 370 | + isTagSelected(field, code) { | ||
| 371 | + const selected = this.form[field] | ||
| 372 | + return Array.isArray(selected) && selected.includes(code) | ||
| 373 | + }, | ||
| 374 | + toggleTag(field, code) { | ||
| 375 | + let selected = this.form[field] | ||
| 376 | + if (!Array.isArray(selected)) { | ||
| 377 | + selected = [] | ||
| 378 | + } | ||
| 379 | + const index = selected.indexOf(code) | ||
| 380 | + if (index > -1) { | ||
| 381 | + selected.splice(index, 1) | ||
| 382 | + } else { | ||
| 383 | + selected.push(code) | ||
| 384 | + } | ||
| 385 | + this.$set(this.form, field, [...selected]) | ||
| 386 | + }, | ||
| 387 | + async initCode() { | ||
| 388 | + try { | ||
| 389 | + const res = await salesmanQuotationGenerateCodeApi() | ||
| 390 | + this.form.code = (res && res.data) ? res.data : '' | ||
| 391 | + } catch (e) { | ||
| 392 | + this.form.code = '' | ||
| 393 | + } | ||
| 394 | + }, | ||
| 395 | + async loadQuoter() { | ||
| 396 | + try { | ||
| 397 | + // 优先使用 store 中已缓存的用户信息 | ||
| 398 | + const storeUser = this.$store && this.$store.state && this.$store.state.user ? this.$store.state.user : {} | ||
| 399 | + if (storeUser.name) { | ||
| 400 | + this.form.quoterName = storeUser.name | ||
| 401 | + return | ||
| 402 | + } | ||
| 403 | + const res = await getInfo() | ||
| 404 | + const _data = res && res.data ? res.data : {} | ||
| 405 | + this.form.quoterName = _data.name || '' | ||
| 406 | + } catch (e) { | ||
| 407 | + this.form.quoterName = '' | ||
| 408 | + } | ||
| 409 | + }, | ||
| 410 | + async loadProducts() { | ||
| 411 | + try { | ||
| 412 | + const res = await breedRelationshipQueryApi({ pageIndex: 1, pageSize: 9999 }) | ||
| 413 | + const _data = res && res.data ? res.data : {} | ||
| 414 | + const list = _data.datas || _data.list || _data.records || [] | ||
| 415 | + this.productList = list.map(it => ({ | ||
| 416 | + label: it.productName || it.name || '', | ||
| 417 | + value: it.productId || it.id || '', | ||
| 418 | + lossRate: it.fixedLossRate != null ? it.fixedLossRate : (it.lossRate != null ? it.lossRate : (it.attritionRate != null ? it.attritionRate : '')) | ||
| 419 | + })) | ||
| 420 | + } catch (e) { | ||
| 421 | + this.productList = [] | ||
| 422 | + } | ||
| 423 | + }, | ||
| 424 | + // 供应商列表数据源(RelateSelectSheet fetchFn) | ||
| 425 | + fetchSuppliers({ pageIndex, pageSize, extra }) { | ||
| 426 | + const name = (extra && (extra.name || extra.keyword || extra.key)) || '' | ||
| 427 | + const params = { | ||
| 428 | + pageIndex, | ||
| 429 | + pageSize, | ||
| 430 | + available: true, | ||
| 431 | + unitName: name, | ||
| 432 | + status: 'PASS', | ||
| 433 | + freeze: false | ||
| 434 | + } | ||
| 435 | + return domesticCustomerCreditQueryApi(params).then(res => { | ||
| 436 | + const _data = res && res.data ? res.data : {} | ||
| 437 | + const records = _data.datas || _data.list || _data.records || [] | ||
| 438 | + const totalCount = _data.totalCount || _data.count || 0 | ||
| 439 | + const hasNext = _data.hasNext || false | ||
| 440 | + return { records, totalCount, hasNext } | ||
| 441 | + }).catch(() => ({ records: [], totalCount: 0, hasNext: false })) | ||
| 442 | + }, | ||
| 443 | + openSupplierSheet() { | ||
| 444 | + this.supplierSheet.selectedKeys = this.form.supplierId ? [this.form.supplierId] : [] | ||
| 445 | + this.supplierSheet.visible = true | ||
| 446 | + }, | ||
| 447 | + onSupplierConfirm({ items }) { | ||
| 448 | + const first = (items && items.length > 0) ? items[0] : null | ||
| 449 | + if (!first) return | ||
| 450 | + this.form.supplierId = first.id || '' | ||
| 451 | + this.form.supplierName = first.unitName || '' | ||
| 452 | + this.form.purchaseDepartmentName = first.purchaseDepartmentName || '' | ||
| 453 | + this.form.regionName = first.regionName || '' | ||
| 454 | + }, | ||
| 455 | + boolText(v) { | ||
| 456 | + if (typeof v !== 'boolean') return '请选择' | ||
| 457 | + return v ? '是' : '否' | ||
| 458 | + }, | ||
| 459 | + openSheet(field) { | ||
| 460 | + const opts = [{ label: '是', value: true }, { label: '否', value: false }] | ||
| 461 | + const cur = this.form[field] | ||
| 462 | + const match = opts.find(o => o.value === cur) | ||
| 463 | + const titleMap = { | ||
| 464 | + longTermOperation: '是否长单操作', | ||
| 465 | + terminalCustomer: '是否终端客户', | ||
| 466 | + priced: '是否未点价', | ||
| 467 | + temporaryPrice: '是否暂定价', | ||
| 468 | + otherExpenseSettlement: '其他费用凭票到厂另行结算', | ||
| 469 | + commodityBuyout: '是否通货买断', | ||
| 470 | + qualityBuyout: '是否质量买断', | ||
| 471 | + quantityBuyout: '是否数量买断', | ||
| 472 | + doorDelivery: '是否送货上门' | ||
| 473 | + } | ||
| 474 | + this.sheet = { visible: true, title: titleMap[field] || '请选择', options: opts, value: match ? match.value : '', field, isDict: false } | ||
| 475 | + }, | ||
| 476 | + openDictSheet(field, dictCode, title) { | ||
| 477 | + const raw = this.getDictOptions(dictCode) || [] | ||
| 478 | + const opts = raw.map(o => ({ label: o.name || o.label || '', value: o.code != null ? o.code : (o.value != null ? o.value : '') })) | ||
| 479 | + const cur = this.form[field] | ||
| 480 | + const match = opts.find(o => String(o.value) === String(cur)) | ||
| 481 | + this.sheet = { visible: true, title: title || '请选择', options: opts, value: match ? match.value : '', field, isDict: true } | ||
| 482 | + }, | ||
| 483 | + getDeliveryMethodLabel() { | ||
| 484 | + const opts = this.getDictOptions('DELIVERY_METHOD') || [] | ||
| 485 | + const m = opts.find(o => String(o.code != null ? o.code : o.value) === String(this.form.deliveryMode)) | ||
| 486 | + return m ? (m.name || m.label || '') : '' | ||
| 487 | + }, | ||
| 488 | + onSheetConfirm({ value }) { | ||
| 489 | + const field = this.sheet.field | ||
| 490 | + if (!field) return | ||
| 491 | + if (this.sheet.isDict) { | ||
| 492 | + this.form[field] = value | ||
| 493 | + } else { | ||
| 494 | + this.form[field] = !!value | ||
| 495 | + // 切换 是否未点价 时,若改为 是 则清空点价截止日期 | ||
| 496 | + if (field === 'priced' && value === true) { | ||
| 497 | + this.form.pricingDeadline = '' | ||
| 498 | + } | ||
| 499 | + } | ||
| 500 | + }, | ||
| 501 | + onRatioBlur() { | ||
| 502 | + let v = parseFloat(this.form.settlementRatio) | ||
| 503 | + if (isNaN(v)) v = '' | ||
| 504 | + else v = Math.round(v * 100) / 100 | ||
| 505 | + this.form.settlementRatio = v | ||
| 506 | + }, | ||
| 507 | + onProductsChange(products) { | ||
| 508 | + this.productLineList = Array.isArray(products) ? products : [] | ||
| 509 | + }, | ||
| 510 | + validateRequired() { | ||
| 511 | + const stringChecks = [ | ||
| 512 | + { key: 'code', label: '编号', msg: '请输入编号' }, | ||
| 513 | + { key: 'supplierId', label: '供应商名称', msg: '请选择供应商' }, | ||
| 514 | + { key: 'validityPeriod', label: '报价时效', msg: '请输入报价时效' }, | ||
| 515 | + { key: 'deliveryMode', label: '交提货方式', msg: '请选择交提货方式' }, | ||
| 516 | + { key: 'invoiceProductName', label: '开票品种', msg: '请输入开票品种' }, | ||
| 517 | + { key: 'deliveryDate', label: '交货日期', msg: '请选择交货日期' }, | ||
| 518 | + { key: 'settlementMethod', label: '结算方式', msg: '请输入结算方式' }, | ||
| 519 | + { key: 'settlementRatio', label: '结算比例', msg: '请输入结算比例' } | ||
| 520 | + ] | ||
| 521 | + for (const it of stringChecks) { | ||
| 522 | + const val = this.form[it.key] | ||
| 523 | + const empty = (val === undefined || val === null || (typeof val === 'string' && val.trim() === '')) | ||
| 524 | + if (empty) { uni.showToast({ title: it.msg, icon: 'none' }); return false } | ||
| 525 | + } | ||
| 526 | + const boolChecks = [ | ||
| 527 | + { key: 'longTermOperation', msg: '请选择是否长单操作' }, | ||
| 528 | + { key: 'terminalCustomer', msg: '请选择是否终端客户' }, | ||
| 529 | + { key: 'priced', msg: '请选择是否未点价' }, | ||
| 530 | + { key: 'otherExpenseSettlement', msg: '请选择其他费用凭票到厂另行结算' }, | ||
| 531 | + { key: 'commodityBuyout', msg: '请选择是否通货买断' }, | ||
| 532 | + { key: 'qualityBuyout', msg: '请选择是否质量买断' }, | ||
| 533 | + { key: 'quantityBuyout', msg: '请选择是否数量买断' }, | ||
| 534 | + { key: 'doorDelivery', msg: '请选择是否送货上门' } | ||
| 535 | + ] | ||
| 536 | + for (const it of boolChecks) { | ||
| 537 | + if (typeof this.form[it.key] !== 'boolean') { | ||
| 538 | + uni.showToast({ title: it.msg, icon: 'none' }) | ||
| 539 | + return false | ||
| 540 | + } | ||
| 541 | + } | ||
| 542 | + // 点价截止日期:是否未点价=是 时必填 | ||
| 543 | + if (this.form.priced === true && !this.form.pricingDeadline) { | ||
| 544 | + uni.showToast({ title: '请选择点价截止日期', icon: 'none' }) | ||
| 545 | + return false | ||
| 546 | + } | ||
| 547 | + // 明细校验 | ||
| 548 | + const list = Array.isArray(this.productLineList) ? this.productLineList : [] | ||
| 549 | + if (list.length === 0) { | ||
| 550 | + uni.showToast({ title: '请添加产品明细', icon: 'none' }) | ||
| 551 | + return false | ||
| 552 | + } | ||
| 553 | + if (this.$refs.productRel && !this.$refs.productRel.validate(this.form.priced)) return false | ||
| 554 | + return true | ||
| 555 | + }, | ||
| 556 | + async onSubmit() { | ||
| 557 | + if (!this.validateRequired()) return | ||
| 558 | + const confirmRes = await new Promise(resolve => { | ||
| 559 | + uni.showModal({ title: '提示', content: '确定新增业务员报价单吗?', confirmText: '确定', cancelText: '取消', success: resolve }) | ||
| 560 | + }) | ||
| 561 | + if (!(confirmRes && confirmRes.confirm)) return | ||
| 562 | + const clean = (obj) => { | ||
| 563 | + const out = {} | ||
| 564 | + Object.keys(obj || {}).forEach(k => { | ||
| 565 | + const v = obj[k] | ||
| 566 | + const isEmptyString = typeof v === 'string' && v.trim() === '' | ||
| 567 | + const isUndef = v === undefined || v === null | ||
| 568 | + const isNaNNumber = typeof v === 'number' && isNaN(v) | ||
| 569 | + if (!(isEmptyString || isUndef || isNaNNumber)) out[k] = v | ||
| 570 | + }) | ||
| 571 | + return out | ||
| 572 | + } | ||
| 573 | + const lines = (this.productLineList || []).map(it => clean(it)) | ||
| 574 | + const materialFields = this.materialConditionConfigs.map(mc => mc.field) | ||
| 575 | + const formCopy = { ...this.form } | ||
| 576 | + materialFields.forEach(f => { | ||
| 577 | + const arr = formCopy[f] | ||
| 578 | + formCopy[f] = Array.isArray(arr) ? arr.join(',') : (arr || '') | ||
| 579 | + }) | ||
| 580 | + const payload = clean({ | ||
| 581 | + ...formCopy, | ||
| 582 | + quotationLineList: lines | ||
| 583 | + }) | ||
| 584 | + try { | ||
| 585 | + await salesmanQuotationSaveApi(payload) | ||
| 586 | + uni.showToast({ title: '新增成功', icon: 'none' }) | ||
| 587 | + try { uni.setStorageSync('SALES_PRICE_LIST_NEED_REFRESH', '1') } catch (e) {} | ||
| 588 | + setTimeout(() => { uni.redirectTo({ url: '/pages/sales-price/index' }) }, 400) | ||
| 589 | + } catch (e) { | ||
| 590 | + uni.showToast({ title: e.msg || '新增失败', icon: 'none' }) | ||
| 591 | + } | ||
| 592 | + } | ||
| 593 | + } | ||
| 594 | +} | ||
| 595 | +</script> | ||
| 596 | +<style lang="scss" scoped> | ||
| 597 | +.page { | ||
| 598 | + display: flex; | ||
| 599 | + flex-direction: column; | ||
| 600 | + height: 100%; | ||
| 601 | +} | ||
| 602 | + | ||
| 603 | +.scroll { | ||
| 604 | + flex: 1; | ||
| 605 | + padding: 12rpx 0 392rpx !important; | ||
| 606 | +} | ||
| 607 | + | ||
| 608 | +.footer { | ||
| 609 | + z-index: 2; | ||
| 610 | + position: fixed; | ||
| 611 | + left: 0; | ||
| 612 | + right: 0; | ||
| 613 | + bottom: 0; | ||
| 614 | + padding: 32rpx; | ||
| 615 | + padding-bottom: calc(32rpx + env(safe-area-inset-bottom)); | ||
| 616 | + background: #fff; | ||
| 617 | + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06); | ||
| 618 | + | ||
| 619 | + .btn { | ||
| 620 | + height: 80rpx; | ||
| 621 | + line-height: 80rpx; | ||
| 622 | + border-radius: 12rpx; | ||
| 623 | + font-size: 32rpx; | ||
| 624 | + } | ||
| 625 | + | ||
| 626 | + .submit { | ||
| 627 | + background: $theme-primary; | ||
| 628 | + color: #fff; | ||
| 629 | + } | ||
| 630 | +} | ||
| 631 | + | ||
| 632 | +::v-deep .uni-list { | ||
| 633 | + .uni-easyinput { | ||
| 634 | + display: flex; | ||
| 635 | + | ||
| 636 | + .uni-input-input { | ||
| 637 | + color: rgba(0, 0, 0, 0.9); | ||
| 638 | + } | ||
| 639 | + } | ||
| 640 | + | ||
| 641 | + .uni-input-placeholder { | ||
| 642 | + z-index: 1; | ||
| 643 | + } | ||
| 644 | + | ||
| 645 | + .uni-input-input { | ||
| 646 | + background-color: #ffffff; | ||
| 647 | + } | ||
| 648 | + | ||
| 649 | + background: transparent; | ||
| 650 | + | ||
| 651 | + &-item { | ||
| 652 | + &__extra-text { | ||
| 653 | + font-size: 32rpx; | ||
| 654 | + } | ||
| 655 | + | ||
| 656 | + &__content-title { | ||
| 657 | + font-size: 32rpx; | ||
| 658 | + color: rgba(0, 0, 0, 0.9); | ||
| 659 | + } | ||
| 660 | + | ||
| 661 | + &__container { | ||
| 662 | + padding: 32rpx; | ||
| 663 | + | ||
| 664 | + .uni-easyinput { | ||
| 665 | + &__placeholder-class { | ||
| 666 | + font-size: 32rpx; | ||
| 667 | + color: rgba(0, 0, 0, 0.4); | ||
| 668 | + } | ||
| 669 | + | ||
| 670 | + &__content { | ||
| 671 | + border: none; | ||
| 672 | + background-color: #ffffff !important; | ||
| 673 | + | ||
| 674 | + &-input { | ||
| 675 | + padding-left: 0 !important; | ||
| 676 | + height: 48rpx; | ||
| 677 | + line-height: 48rpx; | ||
| 678 | + font-size: 32rpx; | ||
| 679 | + } | ||
| 680 | + | ||
| 681 | + .content-clear-icon { | ||
| 682 | + font-size: 44rpx !important; | ||
| 683 | + } | ||
| 684 | + } | ||
| 685 | + } | ||
| 686 | + | ||
| 687 | + .item-title, | ||
| 688 | + .uni-list-item__content { | ||
| 689 | + flex: none; | ||
| 690 | + min-height: 48rpx; | ||
| 691 | + line-height: 48rpx; | ||
| 692 | + font-size: 32rpx; | ||
| 693 | + position: relative; | ||
| 694 | + width: 240rpx; | ||
| 695 | + margin-right: 32rpx; | ||
| 696 | + color: rgba(0, 0, 0, 0.9); | ||
| 697 | + | ||
| 698 | + .required { | ||
| 699 | + color: red; | ||
| 700 | + position: absolute; | ||
| 701 | + top: 50%; | ||
| 702 | + transform: translateY(-50%); | ||
| 703 | + left: -16rpx; | ||
| 704 | + } | ||
| 705 | + } | ||
| 706 | + } | ||
| 707 | + | ||
| 708 | + &.select-item { | ||
| 709 | + &.is-empty { | ||
| 710 | + .uni-list-item__extra-text { | ||
| 711 | + color: rgba(0, 0, 0, 0.4) !important; | ||
| 712 | + } | ||
| 713 | + } | ||
| 714 | + | ||
| 715 | + &.is-filled { | ||
| 716 | + .uni-list-item__extra-text { | ||
| 717 | + color: rgba(0, 0, 0, 0.9) !important; | ||
| 718 | + } | ||
| 719 | + } | ||
| 720 | + | ||
| 721 | + .serial-number-row { | ||
| 722 | + display: flex; | ||
| 723 | + align-items: center; | ||
| 724 | + | ||
| 725 | + .generate-btn { | ||
| 726 | + margin-left: 24rpx; | ||
| 727 | + height: 48rpx; | ||
| 728 | + line-height: 48rpx; | ||
| 729 | + padding: 0 24rpx; | ||
| 730 | + font-size: 24rpx; | ||
| 731 | + border-radius: 8rpx; | ||
| 732 | + background: $theme-primary; | ||
| 733 | + color: #fff; | ||
| 734 | + } | ||
| 735 | + } | ||
| 736 | + } | ||
| 737 | + } | ||
| 738 | +} | ||
| 739 | + | ||
| 740 | +.readonly-text { | ||
| 741 | + color: rgba(0, 0, 0, 0.9); | ||
| 742 | + font-size: 32rpx; | ||
| 743 | + line-height: 48rpx; | ||
| 744 | + text-align: right; | ||
| 745 | + white-space: pre-wrap; | ||
| 746 | + word-break: break-all; | ||
| 747 | +} | ||
| 748 | + | ||
| 749 | +.value-code { | ||
| 750 | + width: 260rpx; | ||
| 751 | + text-align: left; | ||
| 752 | +} | ||
| 753 | + | ||
| 754 | +.material-condition-section, | ||
| 755 | +.remark-section { | ||
| 756 | + margin-top: 20rpx; | ||
| 757 | + background: #fff; | ||
| 758 | +} | ||
| 759 | + | ||
| 760 | +.section-header { | ||
| 761 | + display: flex; | ||
| 762 | + align-items: center; | ||
| 763 | + padding: 24rpx 32rpx; | ||
| 764 | + border-bottom: 1rpx solid #f0f0f0; | ||
| 765 | +} | ||
| 766 | + | ||
| 767 | +.section-title { | ||
| 768 | + font-size: 32rpx; | ||
| 769 | + color: rgba(0, 0, 0, 0.9); | ||
| 770 | + font-weight: 600; | ||
| 771 | +} | ||
| 772 | + | ||
| 773 | +.opCollapse { | ||
| 774 | + width: 32rpx; | ||
| 775 | + height: 28rpx; | ||
| 776 | + margin-right: 16rpx; | ||
| 777 | + margin-top: 8rpx; | ||
| 778 | +} | ||
| 779 | + | ||
| 780 | +.section-content { | ||
| 781 | + padding: 32rpx; | ||
| 782 | +} | ||
| 783 | + | ||
| 784 | +.form-row { | ||
| 785 | + display: flex; | ||
| 786 | + align-items: center; | ||
| 787 | + justify-content: space-between; | ||
| 788 | + margin-bottom: 24rpx; | ||
| 789 | +} | ||
| 790 | + | ||
| 791 | +.form-row:last-child { | ||
| 792 | + margin-bottom: 0; | ||
| 793 | +} | ||
| 794 | + | ||
| 795 | +.form-label { | ||
| 796 | + font-size: 32rpx; | ||
| 797 | + color: rgba(0, 0, 0, 0.9); | ||
| 798 | +} | ||
| 799 | + | ||
| 800 | +.bool-btns { | ||
| 801 | + display: flex; | ||
| 802 | + gap: 20rpx; | ||
| 803 | +} | ||
| 804 | + | ||
| 805 | +.bool-btn { | ||
| 806 | + padding: 12rpx 40rpx; | ||
| 807 | + border: 1rpx solid #ddd; | ||
| 808 | + border-radius: 8rpx; | ||
| 809 | + font-size: 28rpx; | ||
| 810 | + color: #666; | ||
| 811 | + background: #fff; | ||
| 812 | +} | ||
| 813 | + | ||
| 814 | +.bool-btn.active { | ||
| 815 | + background: $theme-primary; | ||
| 816 | + border-color: $theme-primary; | ||
| 817 | + color: #fff; | ||
| 818 | +} | ||
| 819 | + | ||
| 820 | +.material-group { | ||
| 821 | + margin-top: 32rpx; | ||
| 822 | +} | ||
| 823 | + | ||
| 824 | +.material-label { | ||
| 825 | + display: block; | ||
| 826 | + font-size: 30rpx; | ||
| 827 | + color: rgba(0, 0, 0, 0.9); | ||
| 828 | + margin-bottom: 20rpx; | ||
| 829 | +} | ||
| 830 | + | ||
| 831 | +.tag-list { | ||
| 832 | + display: flex; | ||
| 833 | + flex-wrap: wrap; | ||
| 834 | + gap: 16rpx; | ||
| 835 | +} | ||
| 836 | + | ||
| 837 | +.tag-btn { | ||
| 838 | + padding: 12rpx 24rpx; | ||
| 839 | + border: 1rpx solid #ddd; | ||
| 840 | + border-radius: 8rpx; | ||
| 841 | + font-size: 28rpx; | ||
| 842 | + color: #666; | ||
| 843 | + background: #fff; | ||
| 844 | +} | ||
| 845 | + | ||
| 846 | +.tag-btn.active { | ||
| 847 | + background: $theme-primary; | ||
| 848 | + border-color: $theme-primary; | ||
| 849 | + color: #fff; | ||
| 850 | +} | ||
| 851 | + | ||
| 852 | +::v-deep .uni-easyinput { | ||
| 853 | + width: 100%; | ||
| 854 | + | ||
| 855 | + &__content { | ||
| 856 | + background: #f8f8f8 !important; | ||
| 857 | + border-radius: 8rpx; | ||
| 858 | + | ||
| 859 | + &-input { | ||
| 860 | + font-size: 30rpx; | ||
| 861 | + } | ||
| 862 | + } | ||
| 863 | +} | ||
| 864 | +</style> |
pages/sales-price/copy.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="page"> | ||
| 3 | + <scroll-view class="scroll" scroll-y> | ||
| 4 | + <uni-list> | ||
| 5 | + <!-- 编号 --> | ||
| 6 | + <uni-list-item class="select-item" :class="form.code ? 'is-filled' : 'is-empty'"> | ||
| 7 | + <template v-slot:body> | ||
| 8 | + <view class="item-title"><text class="required">*</text><text>编号</text></view> | ||
| 9 | + </template> | ||
| 10 | + <template v-slot:footer> | ||
| 11 | + <view class="serial-number-row"> | ||
| 12 | + <text class="readonly-text value-code">{{ form.code }}</text> | ||
| 13 | + <button class="generate-btn" @click="initCode">点此生成</button> | ||
| 14 | + </view> | ||
| 15 | + </template> | ||
| 16 | + </uni-list-item> | ||
| 17 | + | ||
| 18 | + <!-- 供应商名称 --> | ||
| 19 | + <uni-list-item class="select-item" :class="form.supplierId ? 'is-filled' : 'is-empty'" clickable | ||
| 20 | + @click="openSupplierSheet" :rightText="form.supplierName || '请选择供应商名称'" showArrow> | ||
| 21 | + <template v-slot:body> | ||
| 22 | + <view class="item-title"><text class="required">*</text><text>供应商名称</text></view> | ||
| 23 | + </template> | ||
| 24 | + </uni-list-item> | ||
| 25 | + | ||
| 26 | + <!-- 采购处(带出,禁用) --> | ||
| 27 | + <uni-list-item title="采购处"> | ||
| 28 | + <template v-slot:footer> | ||
| 29 | + <uni-easyinput v-model="form.purchaseDepartmentName" :inputBorder="false" disabled placeholder="选择供应商后自动带出" /> | ||
| 30 | + </template> | ||
| 31 | + </uni-list-item> | ||
| 32 | + | ||
| 33 | + <!-- 区域(带出,禁用) --> | ||
| 34 | + <uni-list-item title="区域"> | ||
| 35 | + <template v-slot:footer> | ||
| 36 | + <uni-easyinput v-model="form.regionName" :inputBorder="false" disabled placeholder="选择供应商后自动带出" /> | ||
| 37 | + </template> | ||
| 38 | + </uni-list-item> | ||
| 39 | + | ||
| 40 | + <!-- 报价时效 --> | ||
| 41 | + <uni-list-item> | ||
| 42 | + <template v-slot:body> | ||
| 43 | + <view class="item-title"><text class="required">*</text><text>报价时效</text></view> | ||
| 44 | + </template> | ||
| 45 | + <template v-slot:footer> | ||
| 46 | + <uni-easyinput v-model="form.validityPeriod" :inputBorder="false" placeholder="请输入报价时效" /> | ||
| 47 | + </template> | ||
| 48 | + </uni-list-item> | ||
| 49 | + | ||
| 50 | + <!-- 报价人(禁用) --> | ||
| 51 | + <uni-list-item title="报价人"> | ||
| 52 | + <template v-slot:footer> | ||
| 53 | + <uni-easyinput v-model="form.quoterName" :inputBorder="false" disabled placeholder="自动获取" /> | ||
| 54 | + </template> | ||
| 55 | + </uni-list-item> | ||
| 56 | + | ||
| 57 | + <!-- 是否长单操作 --> | ||
| 58 | + <uni-list-item class="select-item" :class="typeof form.longTermOperation === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 59 | + @click="openSheet('longTermOperation')" :rightText="boolText(form.longTermOperation)" showArrow> | ||
| 60 | + <template v-slot:body> | ||
| 61 | + <view class="item-title"><text class="required">*</text><text>是否长单操作</text></view> | ||
| 62 | + </template> | ||
| 63 | + </uni-list-item> | ||
| 64 | + | ||
| 65 | + <!-- 是否终端客户 --> | ||
| 66 | + <uni-list-item class="select-item" :class="typeof form.terminalCustomer === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 67 | + @click="openSheet('terminalCustomer')" :rightText="boolText(form.terminalCustomer)" showArrow> | ||
| 68 | + <template v-slot:body> | ||
| 69 | + <view class="item-title"><text class="required">*</text><text>是否终端客户</text></view> | ||
| 70 | + </template> | ||
| 71 | + </uni-list-item> | ||
| 72 | + | ||
| 73 | + <!-- 是否未点价 --> | ||
| 74 | + <uni-list-item class="select-item" :class="typeof form.priced === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 75 | + @click="openSheet('priced')" :rightText="boolText(form.priced)" showArrow> | ||
| 76 | + <template v-slot:body> | ||
| 77 | + <view class="item-title"><text class="required">*</text><text>是否未点价</text></view> | ||
| 78 | + </template> | ||
| 79 | + </uni-list-item> | ||
| 80 | + | ||
| 81 | + <!-- 点价截止日期 - 仅在 是否未点价 = 是 时显示且必填 --> | ||
| 82 | + <uni-list-item v-if="form.priced === true" class="select-item" :class="form.pricingDeadline ? 'is-filled' : 'is-empty'"> | ||
| 83 | + <template v-slot:body> | ||
| 84 | + <view class="item-title"><text class="required">*</text><text>点价截止日期</text></view> | ||
| 85 | + </template> | ||
| 86 | + <template v-slot:footer> | ||
| 87 | + <uni-datetime-picker type="date" v-model="form.pricingDeadline" /> | ||
| 88 | + </template> | ||
| 89 | + </uni-list-item> | ||
| 90 | + | ||
| 91 | + <!-- 是否暂定价 - 仅在 是否未点价 = 是 时显示 --> | ||
| 92 | + <uni-list-item v-if="form.priced === true" class="select-item" :class="typeof form.temporaryPrice === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 93 | + @click="openSheet('temporaryPrice')" :rightText="boolText(form.temporaryPrice)" showArrow> | ||
| 94 | + <template v-slot:body> | ||
| 95 | + <view class="item-title"><text>是否暂定价</text></view> | ||
| 96 | + </template> | ||
| 97 | + </uni-list-item> | ||
| 98 | + | ||
| 99 | + <!-- 其他费用凭票到厂另行结算 --> | ||
| 100 | + <uni-list-item class="select-item" :class="typeof form.otherExpenseSettlement === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 101 | + @click="openSheet('otherExpenseSettlement')" :rightText="boolText(form.otherExpenseSettlement)" showArrow> | ||
| 102 | + <template v-slot:body> | ||
| 103 | + <view class="item-title"><text class="required">*</text><text>其他费用凭票到厂另行结算</text></view> | ||
| 104 | + </template> | ||
| 105 | + </uni-list-item> | ||
| 106 | + | ||
| 107 | + <!-- 交提货方式 --> | ||
| 108 | + <uni-list-item class="select-item" :class="form.deliveryMode ? 'is-filled' : 'is-empty'" clickable | ||
| 109 | + @click="openDictSheet('deliveryMode', 'DELIVERY_METHOD', '交提货方式')" :rightText="getDeliveryMethodLabel() || '请选择交提货方式'" showArrow> | ||
| 110 | + <template v-slot:body> | ||
| 111 | + <view class="item-title"><text class="required">*</text><text>交提货方式</text></view> | ||
| 112 | + </template> | ||
| 113 | + </uni-list-item> | ||
| 114 | + | ||
| 115 | + <!-- 是否通货买断 --> | ||
| 116 | + <uni-list-item class="select-item" :class="typeof form.commodityBuyout === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 117 | + @click="openSheet('commodityBuyout')" :rightText="boolText(form.commodityBuyout)" showArrow> | ||
| 118 | + <template v-slot:body> | ||
| 119 | + <view class="item-title"><text class="required">*</text><text>是否通货买断</text></view> | ||
| 120 | + </template> | ||
| 121 | + </uni-list-item> | ||
| 122 | + | ||
| 123 | + <!-- 是否质量买断 --> | ||
| 124 | + <uni-list-item class="select-item" :class="typeof form.qualityBuyout === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 125 | + @click="openSheet('qualityBuyout')" :rightText="boolText(form.qualityBuyout)" showArrow> | ||
| 126 | + <template v-slot:body> | ||
| 127 | + <view class="item-title"><text class="required">*</text><text>是否质量买断</text></view> | ||
| 128 | + </template> | ||
| 129 | + </uni-list-item> | ||
| 130 | + | ||
| 131 | + <!-- 是否数量买断 --> | ||
| 132 | + <uni-list-item class="select-item" :class="typeof form.quantityBuyout === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 133 | + @click="openSheet('quantityBuyout')" :rightText="boolText(form.quantityBuyout)" showArrow> | ||
| 134 | + <template v-slot:body> | ||
| 135 | + <view class="item-title"><text class="required">*</text><text>是否数量买断</text></view> | ||
| 136 | + </template> | ||
| 137 | + </uni-list-item> | ||
| 138 | + | ||
| 139 | + <!-- 是否送货上门 --> | ||
| 140 | + <uni-list-item class="select-item" :class="typeof form.doorDelivery === 'boolean' ? 'is-filled' : 'is-empty'" clickable | ||
| 141 | + @click="openSheet('doorDelivery')" :rightText="boolText(form.doorDelivery)" showArrow> | ||
| 142 | + <template v-slot:body> | ||
| 143 | + <view class="item-title"><text class="required">*</text><text>是否送货上门</text></view> | ||
| 144 | + </template> | ||
| 145 | + </uni-list-item> | ||
| 146 | + | ||
| 147 | + <!-- 装车费 --> | ||
| 148 | + <uni-list-item title="装车费"> | ||
| 149 | + <template v-slot:footer> | ||
| 150 | + <uni-easyinput v-model="form.loadingFee" type="digit" :inputBorder="false" placeholder="请输入装车费" /> | ||
| 151 | + </template> | ||
| 152 | + </uni-list-item> | ||
| 153 | + | ||
| 154 | + <!-- 开票品种 --> | ||
| 155 | + <uni-list-item> | ||
| 156 | + <template v-slot:body> | ||
| 157 | + <view class="item-title"><text class="required">*</text><text>开票品种</text></view> | ||
| 158 | + </template> | ||
| 159 | + <template v-slot:footer> | ||
| 160 | + <uni-easyinput v-model="form.invoiceProductName" :inputBorder="false" placeholder="请输入开票品种" /> | ||
| 161 | + </template> | ||
| 162 | + </uni-list-item> | ||
| 163 | + | ||
| 164 | + <!-- 交货日期 --> | ||
| 165 | + <uni-list-item> | ||
| 166 | + <template v-slot:body> | ||
| 167 | + <view class="item-title"><text class="required">*</text><text>交货日期</text></view> | ||
| 168 | + </template> | ||
| 169 | + <template v-slot:footer> | ||
| 170 | + <uni-datetime-picker type="date" v-model="form.deliveryDate" /> | ||
| 171 | + </template> | ||
| 172 | + </uni-list-item> | ||
| 173 | + | ||
| 174 | + <!-- 结算方式 --> | ||
| 175 | + <uni-list-item> | ||
| 176 | + <template v-slot:body> | ||
| 177 | + <view class="item-title"><text class="required">*</text><text>结算方式</text></view> | ||
| 178 | + </template> | ||
| 179 | + <template v-slot:footer> | ||
| 180 | + <uni-easyinput v-model="form.settlementMethod" :inputBorder="false" placeholder="请输入结算方式" /> | ||
| 181 | + </template> | ||
| 182 | + </uni-list-item> | ||
| 183 | + | ||
| 184 | + <!-- 结算比例(%) --> | ||
| 185 | + <uni-list-item> | ||
| 186 | + <template v-slot:body> | ||
| 187 | + <view class="item-title"><text class="required">*</text><text>结算比例(%)</text></view> | ||
| 188 | + </template> | ||
| 189 | + <template v-slot:footer> | ||
| 190 | + <uni-easyinput v-model="form.settlementRatio" type="digit" :inputBorder="false" placeholder="请输入结算比例" @blur="onRatioBlur" /> | ||
| 191 | + </template> | ||
| 192 | + </uni-list-item> | ||
| 193 | + | ||
| 194 | + <!-- 协调事由 --> | ||
| 195 | + <uni-list-item title="协调事由"> | ||
| 196 | + <template v-slot:footer> | ||
| 197 | + <uni-easyinput v-model="form.coordinationReason" :inputBorder="false" placeholder="请输入协调事由" disabled /> | ||
| 198 | + </template> | ||
| 199 | + </uni-list-item> | ||
| 200 | + | ||
| 201 | + <!-- 票类状况 --> | ||
| 202 | + <uni-list-item title="票类状况"> | ||
| 203 | + <template v-slot:footer> | ||
| 204 | + <uni-easyinput v-model="form.invoiceTypeStatus" :inputBorder="false" placeholder="请输入票类状况" disabled /> | ||
| 205 | + </template> | ||
| 206 | + </uni-list-item> | ||
| 207 | + | ||
| 208 | + <!-- 明细信息 --> | ||
| 209 | + <ProductRel ref="productRel" mode="add" :options="productList" :priced="form.priced" :list="productLineList" @change="onProductsChange" /> | ||
| 210 | + </uni-list> | ||
| 211 | + | ||
| 212 | + <!-- 料质状况模块(明细下方) --> | ||
| 213 | + <view class="material-condition-section"> | ||
| 214 | + <view class="section-header"> | ||
| 215 | + <image class="opCollapse" src="/static/images/title.png" /> | ||
| 216 | + <text class="section-title">料质状况</text> | ||
| 217 | + </view> | ||
| 218 | + <view class="section-content"> | ||
| 219 | + <view class="form-row"> | ||
| 220 | + <text class="form-label">是否启用料质状况</text> | ||
| 221 | + <view class="bool-btns"> | ||
| 222 | + <view class="bool-btn" :class="{ active: form.materialConditionEnabled === true }" @click="form.materialConditionEnabled = true">是</view> | ||
| 223 | + <view class="bool-btn" :class="{ active: form.materialConditionEnabled === false }" @click="form.materialConditionEnabled = false">否</view> | ||
| 224 | + </view> | ||
| 225 | + </view> | ||
| 226 | + | ||
| 227 | + <template v-if="form.materialConditionEnabled"> | ||
| 228 | + <view v-for="mc in materialConditionConfigs" :key="mc.field" class="material-group"> | ||
| 229 | + <text class="material-label">{{ mc.label }}</text> | ||
| 230 | + <view class="tag-list"> | ||
| 231 | + <view | ||
| 232 | + v-for="opt in getDictOptions(mc.dictCode)" | ||
| 233 | + :key="opt.code" | ||
| 234 | + class="tag-btn" | ||
| 235 | + :class="{ active: isTagSelected(mc.field, opt.code) }" | ||
| 236 | + @click="toggleTag(mc.field, opt.code)" | ||
| 237 | + > | ||
| 238 | + {{ opt.name }} | ||
| 239 | + </view> | ||
| 240 | + </view> | ||
| 241 | + </view> | ||
| 242 | + </template> | ||
| 243 | + </view> | ||
| 244 | + </view> | ||
| 245 | + | ||
| 246 | + <!-- 备注模块 --> | ||
| 247 | + <view class="remark-section"> | ||
| 248 | + <view class="section-header"> | ||
| 249 | + <image class="opCollapse" src="/static/images/title.png" /> | ||
| 250 | + <text class="section-title">备注</text> | ||
| 251 | + </view> | ||
| 252 | + <view class="section-content"> | ||
| 253 | + <uni-easyinput v-model="form.remark" type="textarea" :inputBorder="false" placeholder="请输入备注" maxlength="2000" /> | ||
| 254 | + </view> | ||
| 255 | + </view> | ||
| 256 | + | ||
| 257 | + <view class="footer"> | ||
| 258 | + <button class="btn submit" type="primary" @click="onSubmit">提交</button> | ||
| 259 | + </view> | ||
| 260 | + </scroll-view> | ||
| 261 | + | ||
| 262 | + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" | ||
| 263 | + v-model="sheet.value" @confirm="onSheetConfirm" /> | ||
| 264 | + | ||
| 265 | + <RelateSelectSheet :visible.sync="supplierSheet.visible" :title="supplierSheet.title" | ||
| 266 | + :fetchFn="supplierSheet.fetchFn" :display-fields="supplierSheet.displayFields" | ||
| 267 | + :multiple="false" row-key="id" :selectedKeys.sync="supplierSheet.selectedKeys" | ||
| 268 | + @confirm="onSupplierConfirm" /> | ||
| 269 | + </view> | ||
| 270 | +</template> | ||
| 271 | +<script> | ||
| 272 | +import SingleSelectSheet from '@/components/single-select/index.vue' | ||
| 273 | +import RelateSelectSheet from '@/components/relate-select/index.vue' | ||
| 274 | +import ProductRel from './productRel.vue' | ||
| 275 | +import { salesmanQuotationDetailApi, salesmanQuotationGenerateCodeApi, salesmanQuotationSaveApi, breedRelationshipQueryApi } from '@/api/procure-manage/salesmanQuotation.js' | ||
| 276 | +import { domesticCustomerCreditQueryApi } from '@/api/procure-manage/domesticCustomerCredit.js' | ||
| 277 | +import { getDicByCodes } from '@/utils/dic.js' | ||
| 278 | + | ||
| 279 | +export default { | ||
| 280 | + name: 'CopySalesPrice', | ||
| 281 | + components: { SingleSelectSheet, RelateSelectSheet, ProductRel }, | ||
| 282 | + data() { | ||
| 283 | + return { | ||
| 284 | + sourceId: '', | ||
| 285 | + form: { | ||
| 286 | + code: '', | ||
| 287 | + supplierId: '', | ||
| 288 | + supplierName: '', | ||
| 289 | + purchaseDepartmentName: '', | ||
| 290 | + regionName: '', | ||
| 291 | + validityPeriod: '', | ||
| 292 | + quoterName: '', | ||
| 293 | + longTermOperation: false, | ||
| 294 | + terminalCustomer: false, | ||
| 295 | + priced: true, | ||
| 296 | + pricingDeadline: '', | ||
| 297 | + temporaryPrice: null, | ||
| 298 | + otherExpenseSettlement: false, | ||
| 299 | + deliveryMode: '', | ||
| 300 | + commodityBuyout: false, | ||
| 301 | + qualityBuyout: false, | ||
| 302 | + quantityBuyout: false, | ||
| 303 | + doorDelivery: false, | ||
| 304 | + loadingFee: '', | ||
| 305 | + invoiceProductName: '', | ||
| 306 | + deliveryDate: '', | ||
| 307 | + settlementMethod: '', | ||
| 308 | + settlementRatio: '', | ||
| 309 | + coordinationReason: '', | ||
| 310 | + invoiceTypeStatus: '', | ||
| 311 | + materialConditionEnabled: false, | ||
| 312 | + materialConditionCopperRice: [], | ||
| 313 | + materialConditionBrightCopper: [], | ||
| 314 | + materialConditionFirstClass: [], | ||
| 315 | + materialConditionSecondClass: [], | ||
| 316 | + materialConditionTinCoated: [], | ||
| 317 | + materialConditionScrap: [], | ||
| 318 | + materialConditionWhiteYellow: [], | ||
| 319 | + materialConditionPhosphorCopper: [], | ||
| 320 | + remark: '' | ||
| 321 | + }, | ||
| 322 | + productList: [], | ||
| 323 | + productLineList: [], | ||
| 324 | + sheet: { visible: false, title: '请选择', options: [], value: '', field: '' }, | ||
| 325 | + supplierSheet: { | ||
| 326 | + visible: false, | ||
| 327 | + title: '选择供应商', | ||
| 328 | + fetchFn: null, | ||
| 329 | + displayFields: [ | ||
| 330 | + { label: '单位名称', field: 'unitName' }, | ||
| 331 | + { label: '采购处', field: 'purchaseDepartmentName' }, | ||
| 332 | + { label: '区域', field: 'regionName' } | ||
| 333 | + ], | ||
| 334 | + selectedKeys: [] | ||
| 335 | + }, | ||
| 336 | + materialConditionConfigs: [ | ||
| 337 | + { field: 'materialConditionCopperRice', label: '铜米', dictCode: 'COPPER_RICE' }, | ||
| 338 | + { field: 'materialConditionBrightCopper', label: '光亮铜', dictCode: 'BRIGHT_COPPER' }, | ||
| 339 | + { field: 'materialConditionFirstClass', label: '一特', dictCode: 'FIRST_CLASS' }, | ||
| 340 | + { field: 'materialConditionSecondClass', label: '二特', dictCode: 'SECOND_CLASS' }, | ||
| 341 | + { field: 'materialConditionTinCoated', label: '镀锡紫', dictCode: 'TIN_COATED' }, | ||
| 342 | + { field: 'materialConditionScrap', label: '角料', dictCode: 'SCRAP' }, | ||
| 343 | + { field: 'materialConditionWhiteYellow', label: '镀白黄', dictCode: 'WHITE_YELLOW' }, | ||
| 344 | + { field: 'materialConditionPhosphorCopper', label: '磷铜', dictCode: 'PHOSPHOR_COPPER' } | ||
| 345 | + ], | ||
| 346 | + dictData: {} | ||
| 347 | + } | ||
| 348 | + }, | ||
| 349 | + onLoad(query) { | ||
| 350 | + this.sourceId = (query && query.id) || '' | ||
| 351 | + this.supplierSheet.fetchFn = this.fetchSuppliers.bind(this) | ||
| 352 | + this.loadProducts() | ||
| 353 | + this.loadDictData() | ||
| 354 | + this.loadSourceDetail() | ||
| 355 | + this.initCode() | ||
| 356 | + }, | ||
| 357 | + methods: { | ||
| 358 | + async loadDictData() { | ||
| 359 | + try { | ||
| 360 | + const codes = [...this.materialConditionConfigs.map(mc => mc.dictCode), 'DELIVERY_METHOD'] | ||
| 361 | + const res = await getDicByCodes(codes) | ||
| 362 | + this.dictData = res || {} | ||
| 363 | + } catch (e) { | ||
| 364 | + this.dictData = {} | ||
| 365 | + } | ||
| 366 | + }, | ||
| 367 | + getDictOptions(dictCode) { | ||
| 368 | + const data = this.dictData[dictCode] | ||
| 369 | + return (data && data.data) ? data.data : [] | ||
| 370 | + }, | ||
| 371 | + isTagSelected(field, code) { | ||
| 372 | + const selected = this.form[field] | ||
| 373 | + return Array.isArray(selected) && selected.includes(code) | ||
| 374 | + }, | ||
| 375 | + toggleTag(field, code) { | ||
| 376 | + let selected = this.form[field] | ||
| 377 | + if (!Array.isArray(selected)) { | ||
| 378 | + selected = [] | ||
| 379 | + } | ||
| 380 | + const index = selected.indexOf(code) | ||
| 381 | + if (index > -1) { | ||
| 382 | + selected.splice(index, 1) | ||
| 383 | + } else { | ||
| 384 | + selected.push(code) | ||
| 385 | + } | ||
| 386 | + this.$set(this.form, field, [...selected]) | ||
| 387 | + }, | ||
| 388 | + async initCode() { | ||
| 389 | + try { | ||
| 390 | + const res = await salesmanQuotationGenerateCodeApi() | ||
| 391 | + this.form.code = (res && res.data) ? res.data : '' | ||
| 392 | + } catch (e) { | ||
| 393 | + this.form.code = '' | ||
| 394 | + } | ||
| 395 | + }, | ||
| 396 | + async loadProducts() { | ||
| 397 | + try { | ||
| 398 | + const res = await breedRelationshipQueryApi({ pageIndex: 1, pageSize: 9999 }) | ||
| 399 | + const _data = res && res.data ? res.data : {} | ||
| 400 | + const list = _data.datas || _data.list || _data.records || [] | ||
| 401 | + this.productList = list.map(it => ({ | ||
| 402 | + label: it.productName || it.name || '', | ||
| 403 | + value: it.productId || it.id || '', | ||
| 404 | + lossRate: it.fixedLossRate != null ? it.fixedLossRate : (it.lossRate != null ? it.lossRate : (it.attritionRate != null ? it.attritionRate : '')) | ||
| 405 | + })) | ||
| 406 | + } catch (e) { | ||
| 407 | + this.productList = [] | ||
| 408 | + } | ||
| 409 | + }, | ||
| 410 | + async loadSourceDetail() { | ||
| 411 | + if (!this.sourceId) return | ||
| 412 | + try { | ||
| 413 | + const res = await salesmanQuotationDetailApi({ id: this.sourceId }) | ||
| 414 | + const d = (res && res.data) ? res.data : {} | ||
| 415 | + // 清空 id 和 code,复制为新增 | ||
| 416 | + delete d.id | ||
| 417 | + delete d.code | ||
| 418 | + // 清空明细行的 id 和 itemId | ||
| 419 | + const lineList = Array.isArray(d.quotationLineList) ? d.quotationLineList : (Array.isArray(d.salesmanQuotationLineList) ? d.salesmanQuotationLineList : []) | ||
| 420 | + lineList.forEach(it => { | ||
| 421 | + delete it.id | ||
| 422 | + delete it.itemId | ||
| 423 | + }) | ||
| 424 | + const materialFields = this.materialConditionConfigs.map(mc => mc.field) | ||
| 425 | + materialFields.forEach(f => { | ||
| 426 | + const v = d[f] | ||
| 427 | + d[f] = (typeof v === 'string' && v) ? v.split(',').filter(Boolean) : (Array.isArray(v) ? v : []) | ||
| 428 | + }) | ||
| 429 | + this.form = { ...this.form, ...d } | ||
| 430 | + this.productLineList = lineList | ||
| 431 | + } catch (e) { | ||
| 432 | + uni.showToast({ title: '加载源数据失败', icon: 'none' }) | ||
| 433 | + } | ||
| 434 | + }, | ||
| 435 | + fetchSuppliers({ pageIndex, pageSize, extra }) { | ||
| 436 | + const name = (extra && (extra.name || extra.keyword || extra.key)) || '' | ||
| 437 | + const params = { | ||
| 438 | + pageIndex, | ||
| 439 | + pageSize, | ||
| 440 | + available: true, | ||
| 441 | + unitName: name, | ||
| 442 | + status: 'PASS', | ||
| 443 | + freeze: false | ||
| 444 | + } | ||
| 445 | + return domesticCustomerCreditQueryApi(params).then(res => { | ||
| 446 | + const _data = res && res.data ? res.data : {} | ||
| 447 | + const records = _data.datas || _data.list || _data.records || [] | ||
| 448 | + const totalCount = _data.totalCount || _data.count || 0 | ||
| 449 | + const hasNext = _data.hasNext || false | ||
| 450 | + return { records, totalCount, hasNext } | ||
| 451 | + }).catch(() => ({ records: [], totalCount: 0, hasNext: false })) | ||
| 452 | + }, | ||
| 453 | + openSupplierSheet() { | ||
| 454 | + this.supplierSheet.selectedKeys = this.form.supplierId ? [this.form.supplierId] : [] | ||
| 455 | + this.supplierSheet.visible = true | ||
| 456 | + }, | ||
| 457 | + onSupplierConfirm({ items }) { | ||
| 458 | + const first = (items && items.length > 0) ? items[0] : null | ||
| 459 | + if (!first) return | ||
| 460 | + this.form.supplierId = first.id || '' | ||
| 461 | + this.form.supplierName = first.unitName || '' | ||
| 462 | + this.form.purchaseDepartmentName = first.purchaseDepartmentName || '' | ||
| 463 | + this.form.regionName = first.regionName || '' | ||
| 464 | + }, | ||
| 465 | + boolText(v) { | ||
| 466 | + if (typeof v !== 'boolean') return '请选择' | ||
| 467 | + return v ? '是' : '否' | ||
| 468 | + }, | ||
| 469 | + openSheet(field) { | ||
| 470 | + const opts = [{ label: '是', value: true }, { label: '否', value: false }] | ||
| 471 | + const cur = this.form[field] | ||
| 472 | + const match = opts.find(o => o.value === cur) | ||
| 473 | + const titleMap = { | ||
| 474 | + longTermOperation: '是否长单操作', | ||
| 475 | + terminalCustomer: '是否终端客户', | ||
| 476 | + priced: '是否未点价', | ||
| 477 | + temporaryPrice: '是否暂定价', | ||
| 478 | + otherExpenseSettlement: '其他费用凭票到厂另行结算', | ||
| 479 | + commodityBuyout: '是否通货买断', | ||
| 480 | + qualityBuyout: '是否质量买断', | ||
| 481 | + quantityBuyout: '是否数量买断', | ||
| 482 | + doorDelivery: '是否送货上门' | ||
| 483 | + } | ||
| 484 | + this.sheet = { visible: true, title: titleMap[field] || '请选择', options: opts, value: match ? match.value : '', field, isDict: false } | ||
| 485 | + }, | ||
| 486 | + openDictSheet(field, dictCode, title) { | ||
| 487 | + const raw = this.getDictOptions(dictCode) || [] | ||
| 488 | + const opts = raw.map(o => ({ label: o.name || o.label || '', value: o.code != null ? o.code : (o.value != null ? o.value : '') })) | ||
| 489 | + const cur = this.form[field] | ||
| 490 | + const match = opts.find(o => String(o.value) === String(cur)) | ||
| 491 | + this.sheet = { visible: true, title: title || '请选择', options: opts, value: match ? match.value : '', field, isDict: true } | ||
| 492 | + }, | ||
| 493 | + getDeliveryMethodLabel() { | ||
| 494 | + const opts = this.getDictOptions('DELIVERY_METHOD') || [] | ||
| 495 | + const m = opts.find(o => String(o.code != null ? o.code : o.value) === String(this.form.deliveryMode)) | ||
| 496 | + return m ? (m.name || m.label || '') : '' | ||
| 497 | + }, | ||
| 498 | + onSheetConfirm({ value }) { | ||
| 499 | + const field = this.sheet.field | ||
| 500 | + if (!field) return | ||
| 501 | + if (this.sheet.isDict) { | ||
| 502 | + this.form[field] = value | ||
| 503 | + } else { | ||
| 504 | + this.form[field] = !!value | ||
| 505 | + if (field === 'priced' && value === true) { | ||
| 506 | + this.form.pricingDeadline = '' | ||
| 507 | + } | ||
| 508 | + } | ||
| 509 | + }, | ||
| 510 | + onRatioBlur() { | ||
| 511 | + let v = parseFloat(this.form.settlementRatio) | ||
| 512 | + if (isNaN(v)) v = '' | ||
| 513 | + else v = Math.round(v * 100) / 100 | ||
| 514 | + this.form.settlementRatio = v | ||
| 515 | + }, | ||
| 516 | + onProductsChange(products) { | ||
| 517 | + this.productLineList = Array.isArray(products) ? products : [] | ||
| 518 | + }, | ||
| 519 | + validateRequired() { | ||
| 520 | + const stringChecks = [ | ||
| 521 | + { key: 'code', msg: '请输入编号' }, | ||
| 522 | + { key: 'supplierId', msg: '请选择供应商' }, | ||
| 523 | + { key: 'validityPeriod', msg: '请输入报价时效' }, | ||
| 524 | + { key: 'deliveryMode', msg: '请选择交提货方式' }, | ||
| 525 | + { key: 'invoiceProductName', msg: '请输入开票品种' }, | ||
| 526 | + { key: 'deliveryDate', msg: '请选择交货日期' }, | ||
| 527 | + { key: 'settlementMethod', msg: '请输入结算方式' }, | ||
| 528 | + { key: 'settlementRatio', msg: '请输入结算比例' } | ||
| 529 | + ] | ||
| 530 | + for (const it of stringChecks) { | ||
| 531 | + const val = this.form[it.key] | ||
| 532 | + const empty = (val === undefined || val === null || (typeof val === 'string' && val.trim() === '')) | ||
| 533 | + if (empty) { uni.showToast({ title: it.msg, icon: 'none' }); return false } | ||
| 534 | + } | ||
| 535 | + const boolChecks = [ | ||
| 536 | + { key: 'longTermOperation', msg: '请选择是否长单操作' }, | ||
| 537 | + { key: 'terminalCustomer', msg: '请选择是否终端客户' }, | ||
| 538 | + { key: 'priced', msg: '请选择是否未点价' }, | ||
| 539 | + { key: 'otherExpenseSettlement', msg: '请选择其他费用凭票到厂另行结算' }, | ||
| 540 | + { key: 'commodityBuyout', msg: '请选择是否通货买断' }, | ||
| 541 | + { key: 'qualityBuyout', msg: '请选择是否质量买断' }, | ||
| 542 | + { key: 'quantityBuyout', msg: '请选择是否数量买断' }, | ||
| 543 | + { key: 'doorDelivery', msg: '请选择是否送货上门' } | ||
| 544 | + ] | ||
| 545 | + for (const it of boolChecks) { | ||
| 546 | + if (typeof this.form[it.key] !== 'boolean') { | ||
| 547 | + uni.showToast({ title: it.msg, icon: 'none' }) | ||
| 548 | + return false | ||
| 549 | + } | ||
| 550 | + } | ||
| 551 | + if (this.form.priced === true && !this.form.pricingDeadline) { | ||
| 552 | + uni.showToast({ title: '请选择点价截止日期', icon: 'none' }) | ||
| 553 | + return false | ||
| 554 | + } | ||
| 555 | + const list = Array.isArray(this.productLineList) ? this.productLineList : [] | ||
| 556 | + if (list.length === 0) { | ||
| 557 | + uni.showToast({ title: '请添加产品明细', icon: 'none' }) | ||
| 558 | + return false | ||
| 559 | + } | ||
| 560 | + if (this.$refs.productRel && !this.$refs.productRel.validate(this.form.priced)) return false | ||
| 561 | + return true | ||
| 562 | + }, | ||
| 563 | + async onSubmit() { | ||
| 564 | + if (!this.validateRequired()) return | ||
| 565 | + const confirmRes = await new Promise(resolve => { | ||
| 566 | + uni.showModal({ title: '提示', content: '确定复制提交吗?', confirmText: '确定', cancelText: '取消', success: resolve }) | ||
| 567 | + }) | ||
| 568 | + if (!(confirmRes && confirmRes.confirm)) return | ||
| 569 | + const clean = (obj) => { | ||
| 570 | + const out = {} | ||
| 571 | + Object.keys(obj || {}).forEach(k => { | ||
| 572 | + const v = obj[k] | ||
| 573 | + const isEmptyString = typeof v === 'string' && v.trim() === '' | ||
| 574 | + const isUndef = v === undefined || v === null | ||
| 575 | + const isNaNNumber = typeof v === 'number' && isNaN(v) | ||
| 576 | + if (!(isEmptyString || isUndef || isNaNNumber)) out[k] = v | ||
| 577 | + }) | ||
| 578 | + return out | ||
| 579 | + } | ||
| 580 | + const lines = (this.productLineList || []).map(it => { | ||
| 581 | + const c = clean(it) | ||
| 582 | + delete c.id | ||
| 583 | + delete c.itemId | ||
| 584 | + return c | ||
| 585 | + }) | ||
| 586 | + const materialFields = this.materialConditionConfigs.map(mc => mc.field) | ||
| 587 | + const formCopy = { ...this.form } | ||
| 588 | + delete formCopy.id | ||
| 589 | + materialFields.forEach(f => { | ||
| 590 | + const arr = formCopy[f] | ||
| 591 | + formCopy[f] = Array.isArray(arr) ? arr.join(',') : (arr || '') | ||
| 592 | + }) | ||
| 593 | + const payload = clean({ | ||
| 594 | + ...formCopy, | ||
| 595 | + quotationLineList: lines | ||
| 596 | + }) | ||
| 597 | + try { | ||
| 598 | + await salesmanQuotationSaveApi(payload) | ||
| 599 | + uni.showToast({ title: '复制成功', icon: 'none' }) | ||
| 600 | + try { uni.setStorageSync('SALES_PRICE_LIST_NEED_REFRESH', '1') } catch (e) {} | ||
| 601 | + setTimeout(() => { uni.redirectTo({ url: '/pages/sales-price/index' }) }, 400) | ||
| 602 | + } catch (e) { | ||
| 603 | + uni.showToast({ title: e.msg || '复制失败', icon: 'none' }) | ||
| 604 | + } | ||
| 605 | + } | ||
| 606 | + } | ||
| 607 | +} | ||
| 608 | +</script> | ||
| 609 | +<style lang="scss" scoped> | ||
| 610 | +.page { | ||
| 611 | + display: flex; | ||
| 612 | + flex-direction: column; | ||
| 613 | + height: 100%; | ||
| 614 | +} | ||
| 615 | + | ||
| 616 | +.scroll { | ||
| 617 | + flex: 1; | ||
| 618 | + padding: 12rpx 0 392rpx !important; | ||
| 619 | +} | ||
| 620 | + | ||
| 621 | +.footer { | ||
| 622 | + z-index: 2; | ||
| 623 | + position: fixed; | ||
| 624 | + left: 0; | ||
| 625 | + right: 0; | ||
| 626 | + bottom: 0; | ||
| 627 | + padding: 32rpx; | ||
| 628 | + padding-bottom: calc(32rpx + env(safe-area-inset-bottom)); | ||
| 629 | + background: #fff; | ||
| 630 | + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06); | ||
| 631 | + | ||
| 632 | + .btn { | ||
| 633 | + height: 80rpx; | ||
| 634 | + line-height: 80rpx; | ||
| 635 | + border-radius: 12rpx; | ||
| 636 | + font-size: 32rpx; | ||
| 637 | + } | ||
| 638 | + | ||
| 639 | + .submit { | ||
| 640 | + background: $theme-primary; | ||
| 641 | + color: #fff; | ||
| 642 | + } | ||
| 643 | +} | ||
| 644 | + | ||
| 645 | +::v-deep .uni-list { | ||
| 646 | + .uni-easyinput { | ||
| 647 | + display: flex; | ||
| 648 | + | ||
| 649 | + .uni-input-input { | ||
| 650 | + color: rgba(0, 0, 0, 0.9); | ||
| 651 | + } | ||
| 652 | + } | ||
| 653 | + | ||
| 654 | + .uni-input-placeholder { | ||
| 655 | + z-index: 1; | ||
| 656 | + } | ||
| 657 | + | ||
| 658 | + .uni-input-input { | ||
| 659 | + background-color: #ffffff; | ||
| 660 | + } | ||
| 661 | + | ||
| 662 | + background: transparent; | ||
| 663 | + | ||
| 664 | + &-item { | ||
| 665 | + &__extra-text { | ||
| 666 | + font-size: 32rpx; | ||
| 667 | + } | ||
| 668 | + | ||
| 669 | + &__content-title { | ||
| 670 | + font-size: 32rpx; | ||
| 671 | + color: rgba(0, 0, 0, 0.9); | ||
| 672 | + } | ||
| 673 | + | ||
| 674 | + &__container { | ||
| 675 | + padding: 32rpx; | ||
| 676 | + | ||
| 677 | + .uni-easyinput { | ||
| 678 | + &__placeholder-class { | ||
| 679 | + font-size: 32rpx; | ||
| 680 | + color: rgba(0, 0, 0, 0.4); | ||
| 681 | + } | ||
| 682 | + | ||
| 683 | + &__content { | ||
| 684 | + border: none; | ||
| 685 | + background-color: #ffffff !important; | ||
| 686 | + | ||
| 687 | + &-input { | ||
| 688 | + padding-left: 0 !important; | ||
| 689 | + height: 48rpx; | ||
| 690 | + line-height: 48rpx; | ||
| 691 | + font-size: 32rpx; | ||
| 692 | + } | ||
| 693 | + | ||
| 694 | + .content-clear-icon { | ||
| 695 | + font-size: 44rpx !important; | ||
| 696 | + } | ||
| 697 | + } | ||
| 698 | + } | ||
| 699 | + | ||
| 700 | + .item-title, | ||
| 701 | + .uni-list-item__content { | ||
| 702 | + flex: none; | ||
| 703 | + min-height: 48rpx; | ||
| 704 | + line-height: 48rpx; | ||
| 705 | + font-size: 32rpx; | ||
| 706 | + position: relative; | ||
| 707 | + width: 240rpx; | ||
| 708 | + margin-right: 32rpx; | ||
| 709 | + color: rgba(0, 0, 0, 0.9); | ||
| 710 | + | ||
| 711 | + .required { | ||
| 712 | + color: red; | ||
| 713 | + position: absolute; | ||
| 714 | + top: 50%; | ||
| 715 | + transform: translateY(-50%); | ||
| 716 | + left: -16rpx; | ||
| 717 | + } | ||
| 718 | + } | ||
| 719 | + } | ||
| 720 | + | ||
| 721 | + &.select-item { | ||
| 722 | + &.is-empty { | ||
| 723 | + .uni-list-item__extra-text { | ||
| 724 | + color: rgba(0, 0, 0, 0.4) !important; | ||
| 725 | + } | ||
| 726 | + } | ||
| 727 | + | ||
| 728 | + &.is-filled { | ||
| 729 | + .uni-list-item__extra-text { | ||
| 730 | + color: rgba(0, 0, 0, 0.9) !important; | ||
| 731 | + } | ||
| 732 | + } | ||
| 733 | + | ||
| 734 | + .serial-number-row { | ||
| 735 | + display: flex; | ||
| 736 | + align-items: center; | ||
| 737 | + | ||
| 738 | + .generate-btn { | ||
| 739 | + margin-left: 24rpx; | ||
| 740 | + height: 48rpx; | ||
| 741 | + line-height: 48rpx; | ||
| 742 | + padding: 0 24rpx; | ||
| 743 | + font-size: 24rpx; | ||
| 744 | + border-radius: 8rpx; | ||
| 745 | + background: $theme-primary; | ||
| 746 | + color: #fff; | ||
| 747 | + } | ||
| 748 | + } | ||
| 749 | + } | ||
| 750 | + } | ||
| 751 | +} | ||
| 752 | + | ||
| 753 | +.readonly-text { | ||
| 754 | + color: rgba(0, 0, 0, 0.9); | ||
| 755 | + font-size: 32rpx; | ||
| 756 | + line-height: 48rpx; | ||
| 757 | + text-align: right; | ||
| 758 | + white-space: pre-wrap; | ||
| 759 | + word-break: break-all; | ||
| 760 | +} | ||
| 761 | + | ||
| 762 | +.value-code { | ||
| 763 | + width: 260rpx; | ||
| 764 | + text-align: left; | ||
| 765 | +} | ||
| 766 | + | ||
| 767 | +.material-condition-section, | ||
| 768 | +.remark-section { | ||
| 769 | + margin-top: 20rpx; | ||
| 770 | + background: #fff; | ||
| 771 | +} | ||
| 772 | + | ||
| 773 | +.section-header { | ||
| 774 | + display: flex; | ||
| 775 | + align-items: center; | ||
| 776 | + padding: 24rpx 32rpx; | ||
| 777 | + border-bottom: 1rpx solid #f0f0f0; | ||
| 778 | +} | ||
| 779 | + | ||
| 780 | +.section-title { | ||
| 781 | + font-size: 32rpx; | ||
| 782 | + color: rgba(0, 0, 0, 0.9); | ||
| 783 | + font-weight: 600; | ||
| 784 | +} | ||
| 785 | + | ||
| 786 | +.opCollapse { | ||
| 787 | + width: 32rpx; | ||
| 788 | + height: 28rpx; | ||
| 789 | + margin-right: 16rpx; | ||
| 790 | + margin-top: 8rpx; | ||
| 791 | +} | ||
| 792 | + | ||
| 793 | +.section-content { | ||
| 794 | + padding: 32rpx; | ||
| 795 | +} | ||
| 796 | + | ||
| 797 | +.form-row { | ||
| 798 | + display: flex; | ||
| 799 | + align-items: center; | ||
| 800 | + justify-content: space-between; | ||
| 801 | + margin-bottom: 24rpx; | ||
| 802 | +} | ||
| 803 | + | ||
| 804 | +.form-row:last-child { | ||
| 805 | + margin-bottom: 0; | ||
| 806 | +} | ||
| 807 | + | ||
| 808 | +.form-label { | ||
| 809 | + font-size: 32rpx; | ||
| 810 | + color: rgba(0, 0, 0, 0.9); | ||
| 811 | +} | ||
| 812 | + | ||
| 813 | +.bool-btns { | ||
| 814 | + display: flex; | ||
| 815 | + gap: 20rpx; | ||
| 816 | +} | ||
| 817 | + | ||
| 818 | +.bool-btn { | ||
| 819 | + padding: 12rpx 40rpx; | ||
| 820 | + border: 1rpx solid #ddd; | ||
| 821 | + border-radius: 8rpx; | ||
| 822 | + font-size: 28rpx; | ||
| 823 | + color: #666; | ||
| 824 | + background: #fff; | ||
| 825 | +} | ||
| 826 | + | ||
| 827 | +.bool-btn.active { | ||
| 828 | + background: $theme-primary; | ||
| 829 | + border-color: $theme-primary; | ||
| 830 | + color: #fff; | ||
| 831 | +} | ||
| 832 | + | ||
| 833 | +.material-group { | ||
| 834 | + margin-top: 32rpx; | ||
| 835 | +} | ||
| 836 | + | ||
| 837 | +.material-label { | ||
| 838 | + display: block; | ||
| 839 | + font-size: 30rpx; | ||
| 840 | + color: rgba(0, 0, 0, 0.9); | ||
| 841 | + margin-bottom: 20rpx; | ||
| 842 | +} | ||
| 843 | + | ||
| 844 | +.tag-list { | ||
| 845 | + display: flex; | ||
| 846 | + flex-wrap: wrap; | ||
| 847 | + gap: 16rpx; | ||
| 848 | +} | ||
| 849 | + | ||
| 850 | +.tag-btn { | ||
| 851 | + padding: 12rpx 24rpx; | ||
| 852 | + border: 1rpx solid #ddd; | ||
| 853 | + border-radius: 8rpx; | ||
| 854 | + font-size: 28rpx; | ||
| 855 | + color: #666; | ||
| 856 | + background: #fff; | ||
| 857 | +} | ||
| 858 | + | ||
| 859 | +.tag-btn.active { | ||
| 860 | + background: $theme-primary; | ||
| 861 | + border-color: $theme-primary; | ||
| 862 | + color: #fff; | ||
| 863 | +} | ||
| 864 | + | ||
| 865 | +::v-deep .uni-easyinput { | ||
| 866 | + width: 100%; | ||
| 867 | + | ||
| 868 | + &__content { | ||
| 869 | + background: #f8f8f8 !important; | ||
| 870 | + border-radius: 8rpx; | ||
| 871 | + | ||
| 872 | + &-input { | ||
| 873 | + font-size: 30rpx; | ||
| 874 | + } | ||
| 875 | + } | ||
| 876 | +} | ||
| 877 | +</style> |
pages/sales-price/detail.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="page"> | ||
| 3 | + <scroll-view class="scroll" scroll-y> | ||
| 4 | + <view class="detail-page"> | ||
| 5 | + <!-- 基础信息 --> | ||
| 6 | + <view class="section"> | ||
| 7 | + <text class="row company">{{ safeText(form.code) }}</text> | ||
| 8 | + <view class="row"><text class="label">供应商名称</text><text class="value">{{ safeText(form.supplierName) }}</text></view> | ||
| 9 | + <view class="row"><text class="label">采购处</text><text class="value">{{ safeText(form.purchaseDepartmentName) }}</text></view> | ||
| 10 | + <view class="row"><text class="label">区域</text><text class="value">{{ safeText(form.regionName) }}</text></view> | ||
| 11 | + <view class="row"><text class="label">报价时效</text><text class="value">{{ safeText(form.validityPeriod) }}</text></view> | ||
| 12 | + <view class="row"><text class="label">报价人</text><text class="value">{{ safeText(form.quoterName) }}</text></view> | ||
| 13 | + <view class="row"><text class="label">是否长单操作</text><text class="value">{{ boolText(form.longTermOperation) }}</text></view> | ||
| 14 | + <view class="row"><text class="label">是否终端客户</text><text class="value">{{ boolText(form.terminalCustomer) }}</text></view> | ||
| 15 | + <view class="row"><text class="label">是否未点价</text><text class="value">{{ boolText(form.priced) }}</text></view> | ||
| 16 | + <view v-if="form.priced === true" class="row"><text class="label">点价截止日期</text><text class="value">{{ formatDateOnly(form.pricingDeadline) }}</text></view> | ||
| 17 | + <view v-if="form.priced === true" class="row"><text class="label">是否暂定价</text><text class="value">{{ boolText(form.temporaryPrice) }}</text></view> | ||
| 18 | + <view class="row"><text class="label">其他费用凭票到厂另行结算</text><text class="value">{{ boolText(form.otherExpenseSettlement) }}</text></view> | ||
| 19 | + <view class="row"><text class="label">交提货方式</text><text class="value">{{ getDeliveryMethodLabel() }}</text></view> | ||
| 20 | + <view class="row"><text class="label">是否通货买断</text><text class="value">{{ boolText(form.commodityBuyout) }}</text></view> | ||
| 21 | + <view class="row"><text class="label">是否质量买断</text><text class="value">{{ boolText(form.qualityBuyout) }}</text></view> | ||
| 22 | + <view class="row"><text class="label">是否数量买断</text><text class="value">{{ boolText(form.quantityBuyout) }}</text></view> | ||
| 23 | + <view class="row"><text class="label">是否送货上门</text><text class="value">{{ boolText(form.doorDelivery) }}</text></view> | ||
| 24 | + <view class="row"><text class="label">装车费</text><text class="value">{{ safeText(form.loadingFee) }}</text></view> | ||
| 25 | + <view class="row"><text class="label">开票品种</text><text class="value">{{ safeText(form.invoiceProductName) }}</text></view> | ||
| 26 | + <view class="row"><text class="label">交货日期</text><text class="value">{{ formatDateOnly(form.deliveryDate) }}</text></view> | ||
| 27 | + <view class="row"><text class="label">结算方式</text><text class="value">{{ safeText(form.settlementMethod) }}</text></view> | ||
| 28 | + <view class="row"><text class="label">结算比例(%)</text><text class="value">{{ safeText(form.settlementRatio) }}</text></view> | ||
| 29 | + <view class="row"><text class="label">协调事由</text><text class="value">{{ safeText(form.coordinationReason) }}</text></view> | ||
| 30 | + <view class="row"><text class="label">票类状况</text><text class="value">{{ safeText(form.invoiceTypeStatus) }}</text></view> | ||
| 31 | + </view> | ||
| 32 | + | ||
| 33 | + <!-- 明细信息 --> | ||
| 34 | + <ProductRel mode="view" :list="productLineList" /> | ||
| 35 | + | ||
| 36 | + <!-- 料质状况 --> | ||
| 37 | + <view class="title-header"> | ||
| 38 | + <image class="title-header_icon" src="/static/images/title.png" /> | ||
| 39 | + <span>料质状况</span> | ||
| 40 | + </view> | ||
| 41 | + <view class="section"> | ||
| 42 | + <view class="row"><text class="label">是否启用料质状况</text><text class="value">{{ boolText(form.materialConditionEnabled) }}</text></view> | ||
| 43 | + <template v-if="form.materialConditionEnabled"> | ||
| 44 | + <view v-for="mc in materialConditionConfigs" :key="mc.field" class="material-group"> | ||
| 45 | + <text class="material-label">{{ mc.label }}</text> | ||
| 46 | + <view class="tag-list"> | ||
| 47 | + <view | ||
| 48 | + v-for="opt in getDictOptions(mc.dictCode)" | ||
| 49 | + :key="opt.code" | ||
| 50 | + class="tag-btn" | ||
| 51 | + :class="{ active: isTagSelected(mc.field, opt.code) }" | ||
| 52 | + >{{ opt.name }}</view> | ||
| 53 | + </view> | ||
| 54 | + </view> | ||
| 55 | + </template> | ||
| 56 | + </view> | ||
| 57 | + | ||
| 58 | + <!-- 备注 --> | ||
| 59 | + <view class="title-header"> | ||
| 60 | + <image class="title-header_icon" src="/static/images/title.png" /> | ||
| 61 | + <span>备注</span> | ||
| 62 | + </view> | ||
| 63 | + <view class="section"> | ||
| 64 | + <text class="remark-text">{{ safeText(form.remark) }}</text> | ||
| 65 | + </view> | ||
| 66 | + </view> | ||
| 67 | + </scroll-view> | ||
| 68 | + <detail-buttons :buttons="displayButtons" @click="handleButtonClick" /> | ||
| 69 | + </view> | ||
| 70 | +</template> | ||
| 71 | +<script> | ||
| 72 | +import DetailButtons from '@/components/detail-buttons/index.vue' | ||
| 73 | +import ProductRel from './productRel.vue' | ||
| 74 | +import { salesmanQuotationDetailApi, salesmanQuotationCancelApi } from '@/api/procure-manage/salesmanQuotation.js' | ||
| 75 | +import { getDicByCodes } from '@/utils/dic.js' | ||
| 76 | +import { getInfo } from '@/api/login.js' | ||
| 77 | +export default { | ||
| 78 | + name: 'DetailSalesPrice', | ||
| 79 | + components: { DetailButtons, ProductRel }, | ||
| 80 | + data() { | ||
| 81 | + return { | ||
| 82 | + id: '', | ||
| 83 | + form: {}, | ||
| 84 | + productLineList: [], | ||
| 85 | + materialConditionConfigs: [ | ||
| 86 | + { field: 'materialConditionCopperRice', label: '铜米', dictCode: 'COPPER_RICE' }, | ||
| 87 | + { field: 'materialConditionBrightCopper', label: '光亮铜', dictCode: 'BRIGHT_COPPER' }, | ||
| 88 | + { field: 'materialConditionFirstClass', label: '一特', dictCode: 'FIRST_CLASS' }, | ||
| 89 | + { field: 'materialConditionSecondClass', label: '二特', dictCode: 'SECOND_CLASS' }, | ||
| 90 | + { field: 'materialConditionTinCoated', label: '镀锡紫', dictCode: 'TIN_COATED' }, | ||
| 91 | + { field: 'materialConditionScrap', label: '角料', dictCode: 'SCRAP' }, | ||
| 92 | + { field: 'materialConditionWhiteYellow', label: '镀白黄', dictCode: 'WHITE_YELLOW' }, | ||
| 93 | + { field: 'materialConditionPhosphorCopper', label: '磷铜', dictCode: 'PHOSPHOR_COPPER' } | ||
| 94 | + ], | ||
| 95 | + dictData: {}, | ||
| 96 | + buttons: [ | ||
| 97 | + { text: '编辑', visible: true, variant: 'outline', event: 'edit' }, | ||
| 98 | + { text: '复制', visible: true, variant: 'primary', event: 'copy' }, | ||
| 99 | + { text: '取消', visible: true, variant: 'outline', event: 'cancel' }, | ||
| 100 | + { text: '生成计划', visible: true, variant: 'outline', event: 'plan' }, | ||
| 101 | + { text: '审核', visible: true, variant: 'primary', event: 'approve' }, | ||
| 102 | + { text: '审核详情', visible: true, event: 'approveDetail' }, | ||
| 103 | + ], | ||
| 104 | + investigatorId: '', | ||
| 105 | + } | ||
| 106 | + }, | ||
| 107 | + computed: { | ||
| 108 | + displayButtons() { | ||
| 109 | + const s = this.form.approvalStatus || '' | ||
| 110 | + const c = this.form.createById || '' | ||
| 111 | + const p = this.form.status || '' | ||
| 112 | + return [ | ||
| 113 | + { ...this.buttons[0], visible: (s === 'REFUSE' && c === this.investigatorId && this.$auth.hasPermi('procure-manage:sales-price:modify')) }, | ||
| 114 | + { ...this.buttons[1], visible: this.$auth.hasPermi('procure-manage:sales-price:copy') }, | ||
| 115 | + { ...this.buttons[2], visible: (s === 'REFUSE' && c === this.investigatorId && this.$auth.hasPermi('procure-manage:sales-price:cancel')) }, | ||
| 116 | + { ...this.buttons[3], visible: (p === 'DEAL_CLOSED' && this.$auth.hasPermi('procure-manage:sales-price:create')) }, | ||
| 117 | + { ...this.buttons[4], visible: (s === 'AUDIT' && this.form.showExamine && this.$auth.hasPermi('procure-manage:sales-price:approves')) }, | ||
| 118 | + { ...this.buttons[5], visible: (this.form.showExamineDetail && this.$auth.hasPermi('procure-manage:sales-price:view')) }, | ||
| 119 | + ] | ||
| 120 | + } | ||
| 121 | + }, | ||
| 122 | + onLoad(query) { | ||
| 123 | + this.id = (query && query.id) || '' | ||
| 124 | + this.loadDictData() | ||
| 125 | + this.loadDetail() | ||
| 126 | + // 获取当前用户信息 | ||
| 127 | + this.getUserInfo(); | ||
| 128 | + }, | ||
| 129 | + methods: { | ||
| 130 | + // 获取当前用户信息 | ||
| 131 | + async getUserInfo() { | ||
| 132 | + getInfo() | ||
| 133 | + .then((res) => { | ||
| 134 | + this.investigatorId = res?.id || ''; | ||
| 135 | + }) | ||
| 136 | + .catch((err) => { | ||
| 137 | + console.error('获取用户信息失败:', err); | ||
| 138 | + }); | ||
| 139 | + }, | ||
| 140 | + async loadDictData() { | ||
| 141 | + try { | ||
| 142 | + const codes = [...this.materialConditionConfigs.map(mc => mc.dictCode), 'DELIVERY_METHOD'] | ||
| 143 | + const res = await getDicByCodes(codes) | ||
| 144 | + this.dictData = res || {} | ||
| 145 | + } catch (e) { | ||
| 146 | + this.dictData = {} | ||
| 147 | + } | ||
| 148 | + }, | ||
| 149 | + getDictOptions(dictCode) { | ||
| 150 | + const data = this.dictData[dictCode] | ||
| 151 | + return (data && data.data) ? data.data : [] | ||
| 152 | + }, | ||
| 153 | + isTagSelected(field, code) { | ||
| 154 | + const selected = this.form[field] | ||
| 155 | + return Array.isArray(selected) && selected.includes(code) | ||
| 156 | + }, | ||
| 157 | + boolText(v) { | ||
| 158 | + if (typeof v !== 'boolean') return '-' | ||
| 159 | + return v ? '是' : '否' | ||
| 160 | + }, | ||
| 161 | + getDeliveryMethodLabel() { | ||
| 162 | + const opts = this.getDictOptions('DELIVERY_METHOD') || [] | ||
| 163 | + const m = opts.find(o => String(o.code != null ? o.code : o.value) === String(this.form.deliveryMode)) | ||
| 164 | + return m ? (m.name || m.label || '-') : '-' | ||
| 165 | + }, | ||
| 166 | + formatDateOnly(v) { | ||
| 167 | + const s = v == null ? '' : String(v).trim() | ||
| 168 | + if (!s) return '-' | ||
| 169 | + if (s.length >= 10) return s.slice(0, 10) | ||
| 170 | + return s | ||
| 171 | + }, | ||
| 172 | + safeText(v) { | ||
| 173 | + const s = v == null ? '' : String(v) | ||
| 174 | + return s.trim() ? s : '-' | ||
| 175 | + }, | ||
| 176 | + async loadDetail() { | ||
| 177 | + if (!this.id) return | ||
| 178 | + try { | ||
| 179 | + const res = await salesmanQuotationDetailApi({ id: this.id }) | ||
| 180 | + const d = (res && res.data) ? res.data : {} | ||
| 181 | + const materialFields = this.materialConditionConfigs.map(mc => mc.field) | ||
| 182 | + materialFields.forEach(f => { | ||
| 183 | + const v = d[f] | ||
| 184 | + d[f] = (typeof v === 'string' && v) ? v.split(',').filter(Boolean) : (Array.isArray(v) ? v : []) | ||
| 185 | + }) | ||
| 186 | + this.form = d | ||
| 187 | + this.productLineList = Array.isArray(d.quotationLineList) ? d.quotationLineList : (Array.isArray(d.salesmanQuotationLineList) ? d.salesmanQuotationLineList : []) | ||
| 188 | + } catch (e) { | ||
| 189 | + uni.showToast({ title: '加载详情失败', icon: 'none' }) | ||
| 190 | + } | ||
| 191 | + }, | ||
| 192 | + handleButtonClick(btn) { | ||
| 193 | + if (!btn || btn.disabled) return | ||
| 194 | + const e = btn.event || '' | ||
| 195 | + if (e === 'edit') return this.onEdit() | ||
| 196 | + if (e === 'copy') return this.onCopy() | ||
| 197 | + if (e === 'approve') return this.onApprove() | ||
| 198 | + if (e === 'approveDetail') return this.onApproveDetail() | ||
| 199 | + if (e === 'cancel') return this.onCancel() | ||
| 200 | + }, | ||
| 201 | + onEdit() { | ||
| 202 | + uni.navigateTo({ url: '/pages/sales-price/modify?id=' + this.id }) | ||
| 203 | + }, | ||
| 204 | + onCopy() { | ||
| 205 | + uni.navigateTo({ url: '/pages/sales-price/copy?id=' + this.id }) | ||
| 206 | + }, | ||
| 207 | + onCancel() { | ||
| 208 | + const id = this.id || (this.form && this.form.id) || '' | ||
| 209 | + if (!id) return | ||
| 210 | + uni.showModal({ | ||
| 211 | + title: '系统提示', | ||
| 212 | + content: '是否确定取消该流程?', | ||
| 213 | + confirmText: '确定', | ||
| 214 | + cancelText: '取消', | ||
| 215 | + success: (res) => { | ||
| 216 | + if (res && res.confirm) { | ||
| 217 | + salesmanQuotationCancelApi({ id }).then(() => { | ||
| 218 | + uni.showToast({ title: '已取消', icon: 'none' }) | ||
| 219 | + try { uni.setStorageSync('SALES_PRICE_LIST_NEED_REFRESH', '1') } catch (e) {} | ||
| 220 | + setTimeout(() => { uni.redirectTo({ url: '/pages/supplier-price/index' }) }, 300) | ||
| 221 | + }).catch((e) => { | ||
| 222 | + uni.showToast({ title: (e && e.msg) || '取消失败', icon: 'none' }) | ||
| 223 | + }) | ||
| 224 | + } | ||
| 225 | + } | ||
| 226 | + }) | ||
| 227 | + }, | ||
| 228 | + onApprove() { | ||
| 229 | + const id = this.id || (this.form && this.form.id) || '' | ||
| 230 | + if (!id) return | ||
| 231 | + const CACHE_KEY = 'sourceBusinessId' | ||
| 232 | + const TYPE = 'contractType' | ||
| 233 | + uni.setStorageSync(TYPE, 'SALESMAN_QUOTATION') | ||
| 234 | + uni.setStorageSync(CACHE_KEY, id) | ||
| 235 | + uni.navigateTo({ url: '/pages/flow/audit' }) | ||
| 236 | + }, | ||
| 237 | + onApproveDetail() { | ||
| 238 | + const id = this.id || (this.form && this.form.id) || '' | ||
| 239 | + if (!id) return | ||
| 240 | + const CACHE_KEY = 'sourceBusinessId' | ||
| 241 | + const TYPE = 'contractType' | ||
| 242 | + uni.setStorageSync(TYPE, 'SALESMAN_QUOTATION') | ||
| 243 | + uni.setStorageSync(CACHE_KEY, id) | ||
| 244 | + uni.navigateTo({ url: '/pages/flow/audit_detail' }) | ||
| 245 | + } | ||
| 246 | + } | ||
| 247 | +} | ||
| 248 | +</script> | ||
| 249 | +<style lang="scss" scoped> | ||
| 250 | +.page { | ||
| 251 | + display: flex; | ||
| 252 | + flex-direction: column; | ||
| 253 | + height: 100%; | ||
| 254 | +} | ||
| 255 | + | ||
| 256 | +.scroll { | ||
| 257 | + flex: 1; | ||
| 258 | + padding: 8rpx 0 144rpx; | ||
| 259 | +} | ||
| 260 | + | ||
| 261 | +.detail-page { | ||
| 262 | + background: #f3f3f3; | ||
| 263 | +} | ||
| 264 | + | ||
| 265 | +.title-header { | ||
| 266 | + display: flex; | ||
| 267 | + align-items: center; | ||
| 268 | + padding: 24rpx 32rpx 12rpx; | ||
| 269 | + background-color: #ffffff; | ||
| 270 | + | ||
| 271 | + .title-header_icon { | ||
| 272 | + width: 36rpx; | ||
| 273 | + height: 36rpx; | ||
| 274 | + margin-right: 12rpx; | ||
| 275 | + } | ||
| 276 | + | ||
| 277 | + span { | ||
| 278 | + font-size: 34rpx; | ||
| 279 | + font-weight: 600; | ||
| 280 | + color: rgba(0, 0, 0, 0.9); | ||
| 281 | + } | ||
| 282 | +} | ||
| 283 | + | ||
| 284 | +.section { | ||
| 285 | + padding: 32rpx; | ||
| 286 | + background: #fff; | ||
| 287 | + margin-bottom: 20rpx; | ||
| 288 | +} | ||
| 289 | + | ||
| 290 | +.row { | ||
| 291 | + display: flex; | ||
| 292 | + margin-bottom: 28rpx; | ||
| 293 | + | ||
| 294 | + &:last-child { | ||
| 295 | + margin-bottom: 0; | ||
| 296 | + } | ||
| 297 | + | ||
| 298 | + &.company { | ||
| 299 | + font-size: 36rpx; | ||
| 300 | + font-weight: 600; | ||
| 301 | + color: rgba(0, 0, 0, 0.9); | ||
| 302 | + padding-top: 8rpx; | ||
| 303 | + line-height: 50rpx; | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + .label { | ||
| 307 | + max-width: 420rpx; | ||
| 308 | + margin-right: 20rpx; | ||
| 309 | + line-height: 32rpx; | ||
| 310 | + font-size: 28rpx; | ||
| 311 | + color: rgba(0, 0, 0, 0.6); | ||
| 312 | + } | ||
| 313 | + | ||
| 314 | + .value { | ||
| 315 | + flex: 1; | ||
| 316 | + line-height: 32rpx; | ||
| 317 | + font-size: 28rpx; | ||
| 318 | + color: rgba(0, 0, 0, 0.9); | ||
| 319 | + text-align: right; | ||
| 320 | + word-break: break-all; | ||
| 321 | + } | ||
| 322 | +} | ||
| 323 | + | ||
| 324 | +.line-block { | ||
| 325 | + padding-bottom: 24rpx; | ||
| 326 | + margin-bottom: 24rpx; | ||
| 327 | + border-bottom: 1rpx solid #f0f0f0; | ||
| 328 | + | ||
| 329 | + &:last-child { | ||
| 330 | + border-bottom: none; | ||
| 331 | + margin-bottom: 0; | ||
| 332 | + padding-bottom: 0; | ||
| 333 | + } | ||
| 334 | +} | ||
| 335 | + | ||
| 336 | +.material-group { | ||
| 337 | + margin-top: 32rpx; | ||
| 338 | + | ||
| 339 | + &:first-child { | ||
| 340 | + margin-top: 0; | ||
| 341 | + } | ||
| 342 | +} | ||
| 343 | + | ||
| 344 | +.material-label { | ||
| 345 | + display: block; | ||
| 346 | + font-size: 28rpx; | ||
| 347 | + color: rgba(0, 0, 0, 0.6); | ||
| 348 | + margin-bottom: 20rpx; | ||
| 349 | +} | ||
| 350 | + | ||
| 351 | +.tag-list { | ||
| 352 | + display: flex; | ||
| 353 | + flex-wrap: wrap; | ||
| 354 | + gap: 16rpx; | ||
| 355 | +} | ||
| 356 | + | ||
| 357 | +.tag-btn { | ||
| 358 | + padding: 12rpx 24rpx; | ||
| 359 | + border: 1rpx solid #ddd; | ||
| 360 | + border-radius: 8rpx; | ||
| 361 | + font-size: 28rpx; | ||
| 362 | + color: #999; | ||
| 363 | + background: #f5f5f5; | ||
| 364 | +} | ||
| 365 | + | ||
| 366 | +.tag-btn.active { | ||
| 367 | + background: $theme-primary; | ||
| 368 | + border-color: $theme-primary; | ||
| 369 | + color: #fff; | ||
| 370 | +} | ||
| 371 | + | ||
| 372 | +.remark-text { | ||
| 373 | + font-size: 28rpx; | ||
| 374 | + color: rgba(0, 0, 0, 0.9); | ||
| 375 | + line-height: 1.6; | ||
| 376 | + white-space: pre-wrap; | ||
| 377 | +} | ||
| 378 | + | ||
| 379 | +.empty-tip { | ||
| 380 | + text-align: center; | ||
| 381 | + font-size: 28rpx; | ||
| 382 | + color: rgba(0, 0, 0, 0.4); | ||
| 383 | + padding: 24rpx 0; | ||
| 384 | +} | ||
| 385 | +</style> |
pages/sales-price/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="page"> | ||
| 3 | + <view class="dev-list-fixed"> | ||
| 4 | + <view class="search-row"> | ||
| 5 | + <uni-search-bar v-model="searchKeyword" radius="6" placeholder="请输入供应商名称" clearButton="auto" | ||
| 6 | + cancelButton="none" bgColor="#F3F3F3" textColor="rgba(0,0,0,0.4)" @confirm="search" | ||
| 7 | + @input="onSearchInput" /> | ||
| 8 | + <view class="tool-icons"> | ||
| 9 | + <image v-if="$auth.hasPermi('procure-manage:sales-price:add')" class="tool-icon" src="/static/images/dev_manage/add_icon.png" @click="onAdd" /> | ||
| 10 | + <image class="tool-icon" src="/static/images/dev_manage/filter_icon.png" @click="openFilter" /> | ||
| 11 | + </view> | ||
| 12 | + </view> | ||
| 13 | + </view> | ||
| 14 | + | ||
| 15 | + <view class="list-box"> | ||
| 16 | + <card-list ref="cardRef" :fetch-fn="fetchList" :query="query" :extra="extraParams" row-key="id" | ||
| 17 | + :enable-refresh="true" :enable-load-more="true" @loaded="onCardLoaded" @error="onCardError"> | ||
| 18 | + <template v-slot="{ item }"> | ||
| 19 | + <view class="card" @click.stop="onCardClick(item)"> | ||
| 20 | + <view class="card-header"> | ||
| 21 | + <text class="title omit2">{{ item.supplierName || '-' }}</text> | ||
| 22 | + <text :class="['status', `status_${item.approvalStatus}`]">{{ getAuditStatusText(item.approvalStatus) }}</text> | ||
| 23 | + </view> | ||
| 24 | + <view class="info-row"> | ||
| 25 | + <text>编号</text><text>{{ item.code || '-' }}</text> | ||
| 26 | + </view> | ||
| 27 | + <view class="info-row"> | ||
| 28 | + <text>采购处</text><text>{{ item.purchaseDepartmentName || '-' }}</text> | ||
| 29 | + </view> | ||
| 30 | + <view class="info-row"> | ||
| 31 | + <text>区域</text><text>{{ item.regionName || '-' }}</text> | ||
| 32 | + </view> | ||
| 33 | + <view class="info-row"> | ||
| 34 | + <text>日期</text><text>{{ formatDateOnly(item.quoteTime) }}</text> | ||
| 35 | + </view> | ||
| 36 | + </view> | ||
| 37 | + </template> | ||
| 38 | + </card-list> | ||
| 39 | + </view> | ||
| 40 | + | ||
| 41 | + <filter-modal :visible.sync="filterVisible" :value.sync="filterForm" title="筛选" @reset="onFilterReset" | ||
| 42 | + @confirm="onFilterConfirm"> | ||
| 43 | + <template v-slot="{ model }"> | ||
| 44 | + <view class="filter-form"> | ||
| 45 | + <view class="form-item"> | ||
| 46 | + <view class="label">编号</view> | ||
| 47 | + <uni-easyinput v-model="model.code" placeholder="请输入编号" :inputBorder="false" | ||
| 48 | + placeholderStyle="font-size:14px" @input="onCodeInput" /> | ||
| 49 | + </view> | ||
| 50 | + <view class="form-item"> | ||
| 51 | + <view class="label">报价时间</view> | ||
| 52 | + <uni-datetime-picker type="daterange" v-model="model.dateRange" start="2023-01-01" /> | ||
| 53 | + </view> | ||
| 54 | + </view> | ||
| 55 | + </template> | ||
| 56 | + </filter-modal> | ||
| 57 | + </view> | ||
| 58 | +</template> | ||
| 59 | + | ||
| 60 | +<script> | ||
| 61 | +import CardList from '@/components/card/index.vue' | ||
| 62 | +import FilterModal from '@/components/filter/index.vue' | ||
| 63 | +import { getDicByCodes, getDicName } from '@/utils/dic.js' | ||
| 64 | +import { salesmanQuotationQueryApi } from '@/api/procure-manage/salesmanQuotation.js' | ||
| 65 | + | ||
| 66 | +export default { | ||
| 67 | + name: 'SalesPriceList', | ||
| 68 | + components: { CardList, FilterModal }, | ||
| 69 | + data() { | ||
| 70 | + return { | ||
| 71 | + searchKeyword: '', | ||
| 72 | + searchKeywordDebounced: '', | ||
| 73 | + searchDebounceTimer: null, | ||
| 74 | + query: { | ||
| 75 | + supplierName: '', | ||
| 76 | + code: '', | ||
| 77 | + dateRange: [] | ||
| 78 | + }, | ||
| 79 | + extraParams: {}, | ||
| 80 | + currentItems: [], | ||
| 81 | + filterVisible: false, | ||
| 82 | + filterForm: { | ||
| 83 | + code: '', | ||
| 84 | + dateRange: [] | ||
| 85 | + }, | ||
| 86 | + dicOptions: { | ||
| 87 | + AUDIT_STATUS: [] | ||
| 88 | + }, | ||
| 89 | + } | ||
| 90 | + }, | ||
| 91 | + watch: { | ||
| 92 | + searchKeywordDebounced(v) { | ||
| 93 | + this.query = { ...this.query, supplierName: v || '' } | ||
| 94 | + } | ||
| 95 | + }, | ||
| 96 | + created() { | ||
| 97 | + this.loadDicData() | ||
| 98 | + }, | ||
| 99 | + onShow() { | ||
| 100 | + let needRefresh = '' | ||
| 101 | + try { needRefresh = uni.getStorageSync('SALES_PRICE_LIST_NEED_REFRESH') } catch (e) {} | ||
| 102 | + if (!needRefresh) return | ||
| 103 | + try { uni.removeStorageSync('SALES_PRICE_LIST_NEED_REFRESH') } catch (e) {} | ||
| 104 | + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.reload) { | ||
| 105 | + this.$refs.cardRef.reload() | ||
| 106 | + } | ||
| 107 | + }, | ||
| 108 | + onReachBottom() { | ||
| 109 | + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) { | ||
| 110 | + this.$refs.cardRef.onLoadMore() | ||
| 111 | + } | ||
| 112 | + }, | ||
| 113 | + beforeDestroy() { | ||
| 114 | + if (this.searchDebounceTimer) { | ||
| 115 | + clearTimeout(this.searchDebounceTimer) | ||
| 116 | + this.searchDebounceTimer = null | ||
| 117 | + } | ||
| 118 | + }, | ||
| 119 | + methods: { | ||
| 120 | + onAdd() { | ||
| 121 | + uni.navigateTo({ url: '/pages/sales-price/add' }) | ||
| 122 | + }, | ||
| 123 | + async loadDicData() { | ||
| 124 | + try { | ||
| 125 | + const results = await getDicByCodes(['AUDIT_STATUS']) | ||
| 126 | + this.dicOptions.AUDIT_STATUS = (results.AUDIT_STATUS && results.AUDIT_STATUS.data) || [] | ||
| 127 | + } catch (e) { | ||
| 128 | + this.dicOptions.AUDIT_STATUS = [] | ||
| 129 | + } | ||
| 130 | + }, | ||
| 131 | + formatDateOnly(v) { | ||
| 132 | + const s = v == null ? '' : String(v).trim() | ||
| 133 | + if (!s) return '-' | ||
| 134 | + if (s.length >= 10) return s.slice(0, 10) | ||
| 135 | + return s | ||
| 136 | + }, | ||
| 137 | + onCardLoaded({ items }) { | ||
| 138 | + this.currentItems = items | ||
| 139 | + }, | ||
| 140 | + onCardError() { | ||
| 141 | + uni.showToast({ title: '列表加载失败', icon: 'none' }) | ||
| 142 | + }, | ||
| 143 | + onSearchInput() { | ||
| 144 | + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer) | ||
| 145 | + this.searchDebounceTimer = setTimeout(() => { | ||
| 146 | + this.searchKeywordDebounced = this.searchKeyword | ||
| 147 | + this.searchDebounceTimer = null | ||
| 148 | + }, 1200) | ||
| 149 | + }, | ||
| 150 | + search(e) { | ||
| 151 | + const val = e && e.value != null ? e.value : this.searchKeyword | ||
| 152 | + this.searchKeyword = val | ||
| 153 | + this.searchKeywordDebounced = val | ||
| 154 | + }, | ||
| 155 | + openFilter() { | ||
| 156 | + this.filterForm = { | ||
| 157 | + code: this.query.code || '', | ||
| 158 | + dateRange: Array.isArray(this.query.dateRange) ? this.query.dateRange.slice(0) : [] | ||
| 159 | + } | ||
| 160 | + this.filterVisible = true | ||
| 161 | + }, | ||
| 162 | + onFilterReset(payload) { | ||
| 163 | + this.filterForm = payload | ||
| 164 | + }, | ||
| 165 | + onFilterConfirm(payload) { | ||
| 166 | + this.query = { | ||
| 167 | + supplierName: this.query.supplierName || '', | ||
| 168 | + code: payload.code || '', | ||
| 169 | + dateRange: Array.isArray(payload.dateRange) ? payload.dateRange : [] | ||
| 170 | + } | ||
| 171 | + }, | ||
| 172 | + onCodeInput(val) { | ||
| 173 | + this.filterForm.code = val | ||
| 174 | + }, | ||
| 175 | + getAuditStatusText(status) { | ||
| 176 | + const v = status == null ? '' : String(status) | ||
| 177 | + if (!v) return '-' | ||
| 178 | + return getDicName('AUDIT_STATUS', v, this.dicOptions.AUDIT_STATUS) || v | ||
| 179 | + }, | ||
| 180 | + fetchList({ pageIndex, pageSize, query }) { | ||
| 181 | + const q = query || {} | ||
| 182 | + const range = Array.isArray(q.dateRange) ? q.dateRange : [] | ||
| 183 | + const params = { | ||
| 184 | + pageIndex, | ||
| 185 | + pageSize, | ||
| 186 | + supplierName: q.supplierName || '', | ||
| 187 | + code: q.code || '', | ||
| 188 | + quoteDateStart: (range && range.length === 2) ? range[0] : '', | ||
| 189 | + quoteDateEnd: (range && range.length === 2) ? range[1] : '' | ||
| 190 | + } | ||
| 191 | + return salesmanQuotationQueryApi(params).then(res => { | ||
| 192 | + const _data = res && res.data ? res.data : {} | ||
| 193 | + let records = _data.datas || _data.list || _data.records || [] | ||
| 194 | + const totalCount = _data.totalCount || _data.count || 0 | ||
| 195 | + const hasNext = _data.hasNext || false | ||
| 196 | + records = records.map(it => ({ ...it })) | ||
| 197 | + return { records, totalCount, hasNext } | ||
| 198 | + }).catch(() => { | ||
| 199 | + this.onCardError() | ||
| 200 | + return { records: [], totalCount: 0, hasNext: false } | ||
| 201 | + }) | ||
| 202 | + }, | ||
| 203 | + onCardClick(item) { | ||
| 204 | + uni.navigateTo({ url: '/pages/sales-price/detail?id=' + item.id }) | ||
| 205 | + }, | ||
| 206 | + } | ||
| 207 | +} | ||
| 208 | +</script> | ||
| 209 | + | ||
| 210 | +<style lang="scss" scoped> | ||
| 211 | +.page { | ||
| 212 | + display: flex; | ||
| 213 | + flex-direction: column; | ||
| 214 | + height: 100vh; | ||
| 215 | +} | ||
| 216 | + | ||
| 217 | +.dev-list-fixed { | ||
| 218 | + position: fixed; | ||
| 219 | + top: 96rpx; | ||
| 220 | + left: 0; | ||
| 221 | + right: 0; | ||
| 222 | + z-index: 2; | ||
| 223 | + background: #fff; | ||
| 224 | + | ||
| 225 | + .search-row { | ||
| 226 | + display: flex; | ||
| 227 | + align-items: center; | ||
| 228 | + padding: 16rpx 32rpx; | ||
| 229 | + | ||
| 230 | + .uni-searchbar { | ||
| 231 | + padding: 0; | ||
| 232 | + flex: 1; | ||
| 233 | + } | ||
| 234 | + | ||
| 235 | + .tool-icons { | ||
| 236 | + display: flex; | ||
| 237 | + | ||
| 238 | + .tool-icon { | ||
| 239 | + width: 48rpx; | ||
| 240 | + height: 48rpx; | ||
| 241 | + display: block; | ||
| 242 | + margin-left: 32rpx; | ||
| 243 | + } | ||
| 244 | + } | ||
| 245 | + } | ||
| 246 | +} | ||
| 247 | + | ||
| 248 | +::v-deep .uni-searchbar__box { | ||
| 249 | + height: 80rpx !important; | ||
| 250 | + justify-content: start; | ||
| 251 | + | ||
| 252 | + .uni-searchbar__box-search-input { | ||
| 253 | + font-size: 32rpx !important; | ||
| 254 | + } | ||
| 255 | +} | ||
| 256 | + | ||
| 257 | +.list-box { | ||
| 258 | + flex: 1; | ||
| 259 | + padding-top: 140rpx; | ||
| 260 | + | ||
| 261 | + .card { | ||
| 262 | + position: relative; | ||
| 263 | + } | ||
| 264 | + | ||
| 265 | + .card-header { | ||
| 266 | + margin-bottom: 28rpx; | ||
| 267 | + position: relative; | ||
| 268 | + | ||
| 269 | + .title { | ||
| 270 | + font-size: 36rpx; | ||
| 271 | + font-weight: 600; | ||
| 272 | + line-height: 50rpx; | ||
| 273 | + color: rgba(0, 0, 0, 0.9); | ||
| 274 | + width: 578rpx; | ||
| 275 | + } | ||
| 276 | + | ||
| 277 | + .status { | ||
| 278 | + position: absolute; | ||
| 279 | + top: -32rpx; | ||
| 280 | + right: -12rpx; | ||
| 281 | + height: 48rpx; | ||
| 282 | + line-height: 48rpx; | ||
| 283 | + font-weight: 600; | ||
| 284 | + color: #fff; | ||
| 285 | + font-size: 24rpx; | ||
| 286 | + padding: 0 14rpx; | ||
| 287 | + border-radius: 6rpx; | ||
| 288 | + | ||
| 289 | + &.status_AUDIT { | ||
| 290 | + background: $theme-primary; | ||
| 291 | + } | ||
| 292 | + | ||
| 293 | + &.status_PASS { | ||
| 294 | + background: #2BA471; | ||
| 295 | + } | ||
| 296 | + | ||
| 297 | + &.status_REFUSE { | ||
| 298 | + background: #D54941; | ||
| 299 | + } | ||
| 300 | + | ||
| 301 | + &.status_CANCEL { | ||
| 302 | + background: #E7E7E7; | ||
| 303 | + color: rgba(0, 0, 0, 0.9); | ||
| 304 | + } | ||
| 305 | + } | ||
| 306 | + } | ||
| 307 | + | ||
| 308 | + .info-row { | ||
| 309 | + display: flex; | ||
| 310 | + align-items: center; | ||
| 311 | + color: rgba(0, 0, 0, 0.6); | ||
| 312 | + font-size: 28rpx; | ||
| 313 | + margin-bottom: 24rpx; | ||
| 314 | + height: 32rpx; | ||
| 315 | + | ||
| 316 | + &:last-child { | ||
| 317 | + margin-bottom: 0; | ||
| 318 | + } | ||
| 319 | + | ||
| 320 | + text { | ||
| 321 | + width: 50%; | ||
| 322 | + | ||
| 323 | + &:last-child { | ||
| 324 | + color: rgba(0, 0, 0, 0.9); | ||
| 325 | + width: 50%; | ||
| 326 | + } | ||
| 327 | + } | ||
| 328 | + } | ||
| 329 | +} | ||
| 330 | + | ||
| 331 | +.filter-form { | ||
| 332 | + .form-item { | ||
| 333 | + margin-bottom: 24rpx; | ||
| 334 | + } | ||
| 335 | + | ||
| 336 | + .label { | ||
| 337 | + margin-bottom: 20rpx; | ||
| 338 | + color: rgba(0, 0, 0, 0.9); | ||
| 339 | + height: 44rpx; | ||
| 340 | + line-height: 44rpx; | ||
| 341 | + font-size: 30rpx; | ||
| 342 | + } | ||
| 343 | + | ||
| 344 | + .uni-easyinput { | ||
| 345 | + border: 1rpx solid #f3f3f3; | ||
| 346 | + } | ||
| 347 | +} | ||
| 348 | +</style> |