Commit a20bf1a19bbad92a7cb7675a076da92ddfd62d19
Merge branch 'cjerp-2.0-contract' into publish_cjerp
Showing
12 changed files
with
2134 additions
and
0 deletions
api/procure-manage/domesticAgreement.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | +import { ContentTypeEnum } from '@/utils/httpEnum' | |
| 3 | + | |
| 4 | +export function domesticAgreementQueryApi(params) { | |
| 5 | + return request({ | |
| 6 | + url: '/procurement/contract/query', | |
| 7 | + method: 'get', | |
| 8 | + params | |
| 9 | + }) | |
| 10 | +} | |
| 11 | + | |
| 12 | +export function domesticAgreementDetailApi(params) { | |
| 13 | + return request({ | |
| 14 | + url: '/procurement/contract', | |
| 15 | + method: 'get', | |
| 16 | + params | |
| 17 | + }) | |
| 18 | +} | |
| 19 | + | |
| 20 | +export function domesticAgreementCancelApi(id) { | |
| 21 | + return request({ | |
| 22 | + url: '/procurement/contract/cancel?id=' + encodeURIComponent(id || ''), | |
| 23 | + method: 'put' | |
| 24 | + }) | |
| 25 | +} | |
| 26 | + | |
| 27 | +export function domesticAgreementSubmitApi(id) { | |
| 28 | + return request({ | |
| 29 | + url: '/procurement/contract/submit?id=' + encodeURIComponent(id || ''), | |
| 30 | + method: 'put' | |
| 31 | + }) | |
| 32 | +} | |
| 33 | + | |
| 34 | +export function domesticAgreementEditApi(data) { | |
| 35 | + return request({ | |
| 36 | + url: '/procurement/contract', | |
| 37 | + method: 'put', | |
| 38 | + data, | |
| 39 | + contentType: ContentTypeEnum.JSON | |
| 40 | + }) | |
| 41 | +} | ... | ... |
| ... | ... | @@ -517,6 +517,30 @@ |
| 517 | 517 | } |
| 518 | 518 | }, |
| 519 | 519 | { |
| 520 | + "path": "pages/domestic-agreement/index", | |
| 521 | + "style": { | |
| 522 | + "navigationBarTitleText": "内贸合同管理", | |
| 523 | + "navigationBarBackgroundColor": "#ffffff", | |
| 524 | + "navigationBarTextStyle": "black" | |
| 525 | + } | |
| 526 | + }, | |
| 527 | + { | |
| 528 | + "path": "pages/domestic-agreement/detail", | |
| 529 | + "style": { | |
| 530 | + "navigationBarTitleText": "内贸合同详情", | |
| 531 | + "navigationBarBackgroundColor": "#ffffff", | |
| 532 | + "navigationBarTextStyle": "black" | |
| 533 | + } | |
| 534 | + }, | |
| 535 | + { | |
| 536 | + "path": "pages/domestic-agreement/modify", | |
| 537 | + "style": { | |
| 538 | + "navigationBarTitleText": "编辑内贸合同", | |
| 539 | + "navigationBarBackgroundColor": "#ffffff", | |
| 540 | + "navigationBarTextStyle": "black" | |
| 541 | + } | |
| 542 | + }, | |
| 543 | + { | |
| 520 | 544 | "path": "pages/order_list/index", |
| 521 | 545 | "style": { |
| 522 | 546 | "navigationBarTitleText": "订货单列表", | ... | ... |
pages/domestic-agreement/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.procurementPlanCode) }}</text> | |
| 7 | + <view class="row"> | |
| 8 | + <text class="label">供方</text> | |
| 9 | + <text class="value">{{ safeText(form.supplierName) }}</text> | |
| 10 | + </view> | |
| 11 | + <view class="row"> | |
| 12 | + <text class="label">需方</text> | |
| 13 | + <text class="value">{{ safeText(form.companyFullName) }}</text> | |
| 14 | + </view> | |
| 15 | + <view class="row"> | |
| 16 | + <text class="label">签订地点</text> | |
| 17 | + <text class="value">{{ safeText(form.signPlace, '芜湖市') }}</text> | |
| 18 | + </view> | |
| 19 | + <view class="row"> | |
| 20 | + <text class="label">签订时间</text> | |
| 21 | + <text class="value">{{ formatDateOnly(form.signTime) }}</text> | |
| 22 | + </view> | |
| 23 | + <view class="row"> | |
| 24 | + <text class="label">投诉编码</text> | |
| 25 | + <text class="value">{{ safeText(form.procurementPlanCode) }}</text> | |
| 26 | + </view> | |
| 27 | + <view class="row"> | |
| 28 | + <text class="label">结算比例</text> | |
| 29 | + <text class="value">{{ formatPercent(form.settlementRatio) }}</text> | |
| 30 | + </view> | |
| 31 | + <view v-if="form.createUserName" class="row"> | |
| 32 | + <text class="label">发起人</text> | |
| 33 | + <text class="value">{{ safeText(form.createUserName) }}</text> | |
| 34 | + </view> | |
| 35 | + <view v-if="approvalStatusVisible" class="row"> | |
| 36 | + <text class="label">审核状态</text> | |
| 37 | + <text class="value">{{ getAuditStatusText(form.approvalStatus) }}</text> | |
| 38 | + </view> | |
| 39 | + <view v-if="attachmentList.length" class="row"> | |
| 40 | + <text class="label">附件</text> | |
| 41 | + <view class="attach-list"> | |
| 42 | + <view v-for="(at, idx) in attachmentList" :key="idx" class="attach-item"> | |
| 43 | + <text class="attach-name">{{ at.name }}</text> | |
| 44 | + <text class="attach-view" @click.stop="onPreviewAttachment(at)">查看</text> | |
| 45 | + </view> | |
| 46 | + </view> | |
| 47 | + </view> | |
| 48 | + </view> | |
| 49 | + | |
| 50 | + <ProductRel mode="view" :list="lineList" /> | |
| 51 | + | |
| 52 | + <view v-if="form.specialAgreement" class="title-header"> | |
| 53 | + <image class="title-header_icon" src="/static/images/title.png" /> | |
| 54 | + <span>特殊约定</span> | |
| 55 | + </view> | |
| 56 | + <view v-if="form.specialAgreement" class="section"> | |
| 57 | + <text class="remark-text">{{ safeText(form.specialAgreement) }}</text> | |
| 58 | + </view> | |
| 59 | + </view> | |
| 60 | + </scroll-view> | |
| 61 | + <detail-buttons :buttons="displayButtons" @click="handleButtonClick" /> | |
| 62 | + </view> | |
| 63 | +</template> | |
| 64 | + | |
| 65 | +<script> | |
| 66 | +import DetailButtons from '@/components/detail-buttons/index.vue' | |
| 67 | +import ProductRel from './productRel.vue' | |
| 68 | +import { getInfo } from '@/api/login' | |
| 69 | +import { domesticAgreementCancelApi, domesticAgreementDetailApi, domesticAgreementSubmitApi } from '@/api/procure-manage/domesticAgreement.js' | |
| 70 | +import { getDicByCodes, getDicName } from '@/utils/dic.js' | |
| 71 | + | |
| 72 | +export default { | |
| 73 | + name: 'DomesticAgreementDetail', | |
| 74 | + components: { DetailButtons, ProductRel }, | |
| 75 | + data() { | |
| 76 | + return { | |
| 77 | + id: '', | |
| 78 | + form: {}, | |
| 79 | + lineList: [], | |
| 80 | + attachmentList: [], | |
| 81 | + dicOptions: { | |
| 82 | + AUDIT_STATUS: [] | |
| 83 | + }, | |
| 84 | + buttons: [{ | |
| 85 | + text: '审核详情', | |
| 86 | + visible: true, | |
| 87 | + variant: 'outline', | |
| 88 | + event: 'auditDetail', | |
| 89 | + },{ | |
| 90 | + text: '审核', | |
| 91 | + visible: true, | |
| 92 | + variant: 'primary', | |
| 93 | + event: 'audit', | |
| 94 | + },{ | |
| 95 | + text: '编辑', | |
| 96 | + visible: true, | |
| 97 | + variant: 'outline', | |
| 98 | + event: 'edit', | |
| 99 | + }, | |
| 100 | + { | |
| 101 | + text: '提交审核', | |
| 102 | + visible: true, | |
| 103 | + variant: 'outline', | |
| 104 | + event: 'submitAudit', | |
| 105 | + }, | |
| 106 | + { | |
| 107 | + text: '取消', | |
| 108 | + visible: true, | |
| 109 | + variant: 'outline', | |
| 110 | + event: 'cancel', | |
| 111 | + }], | |
| 112 | + currentUserId: '', | |
| 113 | + } | |
| 114 | + }, | |
| 115 | + computed: { | |
| 116 | + displayButtons() { | |
| 117 | + const row = this.form || {} | |
| 118 | + const status = row.approvalStatus | |
| 119 | + const isDraft = !status; //草稿 | |
| 120 | + const isAudit = status === 'AUDIT'; | |
| 121 | + const isPass = status === 'PASS'; | |
| 122 | + const isRefuse = status === 'REFUSE'; | |
| 123 | + return [ | |
| 124 | + { ...this.buttons[0], visible: (isAudit || isPass)&& this.form?.showExamineDetail === true && this.$auth.hasPermi('agreement-manage:domestic-agreement:view') }, | |
| 125 | + { ...this.buttons[1], visible: isAudit && this.form?.showExamine === true && this.$auth.hasPermi('agreement-manage:domestic-agreement:approve') }, | |
| 126 | + { ...this.buttons[2], visible: this.$auth.hasPermi('agreement-manage:domestic-agreement:modify') }, | |
| 127 | + { ...this.buttons[3], visible: (isDraft || isRefuse) && row.createById === this.currentUserId&& this.$auth.hasPermi('agreement-manage:domestic-agreement:submit') }, | |
| 128 | + { ...this.buttons[4], visible:(isRefuse || !status) && this.currentUserId === row?.createById && this.$auth.hasPermi('agreement-manage:domestic-agreement:cancel') }, | |
| 129 | + ] | |
| 130 | + }, | |
| 131 | + approvalStatusVisible() { | |
| 132 | + return !!(this.form && this.form.approvalStatus) | |
| 133 | + } | |
| 134 | + }, | |
| 135 | + onLoad(query) { | |
| 136 | + this.id = (query && query.id) || '' | |
| 137 | + this.loadDicData() | |
| 138 | + this.loadDetail() | |
| 139 | + this.getUserInfo() | |
| 140 | + }, | |
| 141 | + onShow() { | |
| 142 | + let needRefresh = '' | |
| 143 | + try { needRefresh = uni.getStorageSync('DOMESTIC_AGREEMENT_DETAIL_NEED_REFRESH') } catch (e) {} | |
| 144 | + if (!needRefresh) return | |
| 145 | + try { uni.removeStorageSync('DOMESTIC_AGREEMENT_DETAIL_NEED_REFRESH') } catch (e) {} | |
| 146 | + this.loadDetail() | |
| 147 | + }, | |
| 148 | + methods: { | |
| 149 | + handleButtonClick(btn) { | |
| 150 | + if (!btn || btn.disabled) return | |
| 151 | + var e = btn.event || '' | |
| 152 | + if (e === 'cancel') return this.onCancel() | |
| 153 | + if (e === 'submitAudit') return this.onSubmitAudit() | |
| 154 | + if (e === 'edit') return this.onEdit() | |
| 155 | + if (e === 'audit') return this.onAudit() | |
| 156 | + if (e === 'auditDetail') return this.onAuditDetail() | |
| 157 | + uni.showToast({ title: (btn.text || '操作') + '待实现', icon: 'none' }) | |
| 158 | + }, | |
| 159 | + onAudit() { | |
| 160 | + const id = this.id || (this.form && this.form.id) || '' | |
| 161 | + if (!id) return | |
| 162 | + const CACHE_KEY = 'sourceBusinessId' | |
| 163 | + const TYPE = 'contractType' | |
| 164 | + uni.setStorageSync(TYPE, 'PROCUREMENT_CONTRACT') | |
| 165 | + uni.setStorageSync(CACHE_KEY, id) | |
| 166 | + uni.navigateTo({ url: '/pages/flow/audit' }) | |
| 167 | + }, | |
| 168 | + onAuditDetail() { | |
| 169 | + const id = this.id || (this.form && this.form.id) || '' | |
| 170 | + if (!id) return | |
| 171 | + const CACHE_KEY = 'sourceBusinessId' | |
| 172 | + const TYPE = 'contractType' | |
| 173 | + uni.setStorageSync(TYPE, 'PROCUREMENT_CONTRACT') | |
| 174 | + uni.setStorageSync(CACHE_KEY, id) | |
| 175 | + uni.navigateTo({ url: '/pages/flow/audit_detail' }) | |
| 176 | + }, | |
| 177 | + onEdit() { | |
| 178 | + uni.navigateTo({ | |
| 179 | + url: '/pages/domestic-agreement/modify?id=' + this.id | |
| 180 | + }) | |
| 181 | + }, | |
| 182 | + refreshListFlags() { | |
| 183 | + try { uni.setStorageSync('DOMESTIC_AGREEMENT_LIST_NEED_REFRESH', '1') } catch (e) {} | |
| 184 | + try { uni.setStorageSync('DOMESTIC_AGREEMENT_DETAIL_NEED_REFRESH', '1') } catch (e) {} | |
| 185 | + }, | |
| 186 | + runWithConfirm(opts) { | |
| 187 | + var self = this | |
| 188 | + var title = opts.title || '提示' | |
| 189 | + var content = opts.content || '' | |
| 190 | + var run = opts.run | |
| 191 | + var loading = opts.loading || '处理中' | |
| 192 | + var successText = opts.successText || '操作成功' | |
| 193 | + var failText = opts.failText || '操作失败' | |
| 194 | + if (!this.id) { | |
| 195 | + uni.showToast({ title: '缺少合同ID', icon: 'none' }) | |
| 196 | + return | |
| 197 | + } | |
| 198 | + var apiFn = function () { | |
| 199 | + uni.showLoading({ title: loading, mask: true }) | |
| 200 | + Promise.resolve(run(self.id)).then(function () { | |
| 201 | + uni.hideLoading() | |
| 202 | + uni.showToast({ title: successText, icon: 'none' }) | |
| 203 | + self.refreshListFlags() | |
| 204 | + self.loadDetail() | |
| 205 | + }).catch(function (e) { | |
| 206 | + uni.hideLoading() | |
| 207 | + uni.showToast({ title: (e && (e.msg || e.message)) ? (e.msg || e.message) : failText, icon: 'none' }) | |
| 208 | + }) | |
| 209 | + } | |
| 210 | + uni.showModal({ | |
| 211 | + title: title, | |
| 212 | + content: content, | |
| 213 | + confirmText: '确定', | |
| 214 | + cancelText: '取消', | |
| 215 | + success: function (res) { | |
| 216 | + if (!res || !res.confirm) return | |
| 217 | + apiFn() | |
| 218 | + } | |
| 219 | + }) | |
| 220 | + }, | |
| 221 | + onCancel() { | |
| 222 | + this.runWithConfirm({ | |
| 223 | + title: '取消', | |
| 224 | + content: '确认取消该合同吗?', | |
| 225 | + loading: '提交中', | |
| 226 | + successText: '取消成功', | |
| 227 | + failText: '取消失败', | |
| 228 | + run: function (id) { return domesticAgreementCancelApi(id) } | |
| 229 | + }) | |
| 230 | + }, | |
| 231 | + onSubmitAudit() { | |
| 232 | + this.runWithConfirm({ | |
| 233 | + title: '提交审核', | |
| 234 | + content: '确认提交审核吗?', | |
| 235 | + loading: '提交中', | |
| 236 | + successText: '提交成功', | |
| 237 | + failText: '提交审核失败', | |
| 238 | + run: function (id) { return domesticAgreementSubmitApi(id) } | |
| 239 | + }) | |
| 240 | + }, | |
| 241 | + async getUserInfo() { | |
| 242 | + try { | |
| 243 | + var res = await getInfo() | |
| 244 | + this.currentUserId = (res && res.id) ? res.id : '' | |
| 245 | + } catch (e) { | |
| 246 | + this.currentUserId = '' | |
| 247 | + } | |
| 248 | + }, | |
| 249 | + async loadDicData() { | |
| 250 | + try { | |
| 251 | + const results = await getDicByCodes(['AUDIT_STATUS']) | |
| 252 | + this.dicOptions.AUDIT_STATUS = (results.AUDIT_STATUS && results.AUDIT_STATUS.data) || [] | |
| 253 | + } catch (e) { | |
| 254 | + this.dicOptions.AUDIT_STATUS = [] | |
| 255 | + } | |
| 256 | + }, | |
| 257 | + getAuditStatusText(status) { | |
| 258 | + const v = status == null ? '' : String(status) | |
| 259 | + if (!v) return '-' | |
| 260 | + return getDicName('AUDIT_STATUS', v, this.dicOptions.AUDIT_STATUS) || v | |
| 261 | + }, | |
| 262 | + loadDetail() { | |
| 263 | + if (!this.id) { | |
| 264 | + uni.showToast({ title: '缺少合同ID', icon: 'none' }) | |
| 265 | + return | |
| 266 | + } | |
| 267 | + uni.showLoading && uni.showLoading({ title: '加载中...', mask: true }) | |
| 268 | + this.fetchDetail({ id: this.id }) | |
| 269 | + .then(res => { | |
| 270 | + const data = res && res.data ? (res.data.data || res.data) : {} | |
| 271 | + this.form = Object.assign({}, data) | |
| 272 | + const lines = data && Array.isArray(data.procurementContractLineList) ? data.procurementContractLineList : [] | |
| 273 | + this.lineList = lines.map(l => Object.assign({}, l)) | |
| 274 | + this.buildAttachmentList() | |
| 275 | + this.notifyListRefresh() | |
| 276 | + }) | |
| 277 | + .catch(() => { | |
| 278 | + uni.showToast({ title: '详情加载失败', icon: 'none' }) | |
| 279 | + }) | |
| 280 | + .finally(() => { | |
| 281 | + uni.hideLoading && uni.hideLoading() | |
| 282 | + }) | |
| 283 | + }, | |
| 284 | + fetchDetail(params) { | |
| 285 | + const self = this | |
| 286 | + return domesticAgreementDetailApi(params).catch(function () { | |
| 287 | + return self.mockDetail(params) | |
| 288 | + }) | |
| 289 | + }, | |
| 290 | + mockDetail(params) { | |
| 291 | + return new Promise(resolve => { | |
| 292 | + const mock = { | |
| 293 | + id: params.id, | |
| 294 | + procurementPlanId: 'plan-' + params.id, | |
| 295 | + procurementPlanCode: 'NMHT2026000' + params.id, | |
| 296 | + supplierId: 'S001', | |
| 297 | + supplierName: '上海钢材贸易有限公司', | |
| 298 | + companyShortId: 'C001', | |
| 299 | + companyFullName: '北京远大集团有限公司', | |
| 300 | + signPlace: '芜湖市', | |
| 301 | + signTime: '2026-08-15', | |
| 302 | + deliveryTime: '2026-09-20', | |
| 303 | + settlementRatio: 80, | |
| 304 | + specialAgreement: '1. 本合同项下货物质量须符合国标及双方约定的技术标准;\n2. 如出现质量问题,供方须在3个工作日内响应处理;\n3. 价格波动超过±5%时,双方另行协商结算。', | |
| 305 | + attachmentFileIds: 'f1,f2', | |
| 306 | + attachmentFileNames: '内贸合同扫描件.pdf,补充条款.docx', | |
| 307 | + createUserName: '张三', | |
| 308 | + approvalStatus: 'AUDIT', | |
| 309 | + procurementContractLineList: [ | |
| 310 | + { | |
| 311 | + id: 'L1', | |
| 312 | + contractId: params.id, | |
| 313 | + itemId: 'I1', | |
| 314 | + planLineId: 'PL1', | |
| 315 | + invoiceProductName: '废铜', | |
| 316 | + productId: 'P001', | |
| 317 | + productName: '光亮铜', | |
| 318 | + quantity: '25.500', | |
| 319 | + unitPrice: '62500.00', | |
| 320 | + deliveryTime: '2026-09-15' | |
| 321 | + }, | |
| 322 | + { | |
| 323 | + id: 'L2', | |
| 324 | + contractId: params.id, | |
| 325 | + itemId: 'I2', | |
| 326 | + planLineId: 'PL2', | |
| 327 | + invoiceProductName: '废铜', | |
| 328 | + productId: 'P002', | |
| 329 | + productName: '一特铜', | |
| 330 | + quantity: '18.200', | |
| 331 | + unitPrice: '61800.00', | |
| 332 | + deliveryTime: '2026-09-20' | |
| 333 | + }, | |
| 334 | + { | |
| 335 | + id: 'L3', | |
| 336 | + contractId: params.id, | |
| 337 | + itemId: 'I3', | |
| 338 | + planLineId: 'PL3', | |
| 339 | + invoiceProductName: '废铝', | |
| 340 | + productId: 'P003', | |
| 341 | + productName: '高纯铝锭', | |
| 342 | + quantity: '42.000', | |
| 343 | + unitPrice: '19800.00', | |
| 344 | + deliveryTime: '2026-09-25' | |
| 345 | + } | |
| 346 | + ] | |
| 347 | + } | |
| 348 | + setTimeout(() => resolve({ data: { data: mock } }), 200) | |
| 349 | + }) | |
| 350 | + }, | |
| 351 | + buildAttachmentList() { | |
| 352 | + const ids = this.form.attachmentFileIds | |
| 353 | + const names = this.form.attachmentFileNames | |
| 354 | + const idArr = (typeof ids === 'string' && ids) ? ids.split(',').filter(Boolean) : (Array.isArray(ids) ? ids : []) | |
| 355 | + const nameArr = (typeof names === 'string' && names) ? names.split(',').filter(Boolean) : (Array.isArray(names) ? names : []) | |
| 356 | + const len = Math.max(idArr.length, nameArr.length) | |
| 357 | + const list = [] | |
| 358 | + for (let i = 0; i < len; i++) { | |
| 359 | + list.push({ id: idArr[i] || '', name: nameArr[i] || ('附件' + (i + 1)) }) | |
| 360 | + } | |
| 361 | + this.attachmentList = list | |
| 362 | + }, | |
| 363 | + notifyListRefresh() { | |
| 364 | + try { uni.setStorageSync('DOMESTIC_AGREEMENT_LIST_NEED_REFRESH', '1') } catch (e) {} | |
| 365 | + }, | |
| 366 | + safeText(v, def) { | |
| 367 | + const s = v == null ? '' : String(v) | |
| 368 | + if (s.trim()) return s | |
| 369 | + return def != null ? def : '-' | |
| 370 | + }, | |
| 371 | + formatDateOnly(v) { | |
| 372 | + const s = v == null ? '' : String(v).trim() | |
| 373 | + if (!s) return '-' | |
| 374 | + if (s.length >= 10) return s.slice(0, 10) | |
| 375 | + return s | |
| 376 | + }, | |
| 377 | + formatPercent(v) { | |
| 378 | + if (v === null || v === undefined || v === '') return '-' | |
| 379 | + const n = Number(v) | |
| 380 | + if (isNaN(n)) return String(v) | |
| 381 | + return n + '%' | |
| 382 | + }, | |
| 383 | + onPreviewAttachment(at) { | |
| 384 | + if (!at || !at.id) { | |
| 385 | + uni.showToast({ title: '无法查看', icon: 'none' }) | |
| 386 | + return | |
| 387 | + } | |
| 388 | + uni.showToast({ title: '查看附件 ' + at.name, icon: 'none' }) | |
| 389 | + } | |
| 390 | + } | |
| 391 | +} | |
| 392 | +</script> | |
| 393 | + | |
| 394 | +<style lang="scss" scoped> | |
| 395 | +.page { | |
| 396 | + display: flex; | |
| 397 | + flex-direction: column; | |
| 398 | + height: 100%; | |
| 399 | +} | |
| 400 | +.scroll { | |
| 401 | + flex: 1; | |
| 402 | + padding: 8rpx 0 144rpx; | |
| 403 | +} | |
| 404 | +.detail-page { | |
| 405 | + background: #f3f3f3; | |
| 406 | +} | |
| 407 | +.title-header { | |
| 408 | + display: flex; | |
| 409 | + align-items: center; | |
| 410 | + padding: 24rpx 32rpx 12rpx; | |
| 411 | + background-color: #ffffff; | |
| 412 | + .title-header_icon { | |
| 413 | + width: 36rpx; | |
| 414 | + height: 36rpx; | |
| 415 | + margin-right: 12rpx; | |
| 416 | + } | |
| 417 | + span { | |
| 418 | + font-size: 34rpx; | |
| 419 | + font-weight: 600; | |
| 420 | + color: rgba(0, 0, 0, 0.9); | |
| 421 | + } | |
| 422 | +} | |
| 423 | +.section { | |
| 424 | + padding: 32rpx; | |
| 425 | + background: #fff; | |
| 426 | + margin-bottom: 20rpx; | |
| 427 | +} | |
| 428 | +.row { | |
| 429 | + display: flex; | |
| 430 | + margin-bottom: 28rpx; | |
| 431 | + &:last-child { margin-bottom: 0; } | |
| 432 | + &.company { | |
| 433 | + font-size: 36rpx; | |
| 434 | + font-weight: 600; | |
| 435 | + color: rgba(0, 0, 0, 0.9); | |
| 436 | + padding-top: 8rpx; | |
| 437 | + line-height: 50rpx; | |
| 438 | + } | |
| 439 | + .label { | |
| 440 | + max-width: 420rpx; | |
| 441 | + margin-right: 20rpx; | |
| 442 | + line-height: 32rpx; | |
| 443 | + font-size: 28rpx; | |
| 444 | + color: rgba(0, 0, 0, 0.6); | |
| 445 | + } | |
| 446 | + .value { | |
| 447 | + flex: 1; | |
| 448 | + line-height: 32rpx; | |
| 449 | + font-size: 28rpx; | |
| 450 | + color: rgba(0, 0, 0, 0.9); | |
| 451 | + text-align: right; | |
| 452 | + word-break: break-all; | |
| 453 | + } | |
| 454 | +} | |
| 455 | +.attach-list { | |
| 456 | + flex: 1; | |
| 457 | + display: flex; | |
| 458 | + flex-direction: column; | |
| 459 | + align-items: flex-end; | |
| 460 | + gap: 8rpx; | |
| 461 | +} | |
| 462 | +.attach-item { | |
| 463 | + display: flex; | |
| 464 | + align-items: center; | |
| 465 | + gap: 16rpx; | |
| 466 | + .attach-name { | |
| 467 | + font-size: 26rpx; | |
| 468 | + color: rgba(0, 0, 0, 0.9); | |
| 469 | + } | |
| 470 | + .attach-view { | |
| 471 | + font-size: 26rpx; | |
| 472 | + color: $theme-primary; | |
| 473 | + } | |
| 474 | +} | |
| 475 | +.remark-text { | |
| 476 | + font-size: 28rpx; | |
| 477 | + color: rgba(0, 0, 0, 0.9); | |
| 478 | + line-height: 1.6; | |
| 479 | + white-space: pre-wrap; | |
| 480 | +} | |
| 481 | +.empty-tip { | |
| 482 | + text-align: center; | |
| 483 | + font-size: 28rpx; | |
| 484 | + color: rgba(0, 0, 0, 0.4); | |
| 485 | + padding: 24rpx 0; | |
| 486 | +} | |
| 487 | +</style> | ... | ... |
| 1 | +<template> | |
| 2 | + <view class="detail-page"> | |
| 3 | + <scroll-view class="scroll" scroll-y> | |
| 4 | + <view class="section"> | |
| 5 | + <text class="row company">{{ safeText(form.procurementPlanCode) }}</text> | |
| 6 | + <view class="row"> | |
| 7 | + <text class="label">供方</text> | |
| 8 | + <text class="value">{{ safeText(form.supplierName) }}</text> | |
| 9 | + </view> | |
| 10 | + <view class="row"> | |
| 11 | + <text class="label">需方</text> | |
| 12 | + <text class="value">{{ safeText(form.companyFullName) }}</text> | |
| 13 | + </view> | |
| 14 | + <view class="row"> | |
| 15 | + <text class="label">签订地点</text> | |
| 16 | + <text class="value">{{ safeText(form.signPlace, '芜湖市') }}</text> | |
| 17 | + </view> | |
| 18 | + <view class="row"> | |
| 19 | + <text class="label">签订时间</text> | |
| 20 | + <text class="value">{{ formatDateOnly(form.signTime) }}</text> | |
| 21 | + </view> | |
| 22 | + <view class="row"> | |
| 23 | + <text class="label">投诉编码</text> | |
| 24 | + <text class="value">{{ safeText(form.procurementPlanCode) }}</text> | |
| 25 | + </view> | |
| 26 | + <view class="row"> | |
| 27 | + <text class="label">结算比例</text> | |
| 28 | + <text class="value">{{ formatPercent(form.settlementRatio) }}</text> | |
| 29 | + </view> | |
| 30 | + <view v-if="form.createUserName" class="row"> | |
| 31 | + <text class="label">发起人</text> | |
| 32 | + <text class="value">{{ safeText(form.createUserName) }}</text> | |
| 33 | + </view> | |
| 34 | + <view v-if="approvalStatusVisible" class="row"> | |
| 35 | + <text class="label">审核状态</text> | |
| 36 | + <text class="value">{{ getAuditStatusText(form.approvalStatus) }}</text> | |
| 37 | + </view> | |
| 38 | + <view v-if="attachmentList.length" class="row"> | |
| 39 | + <text class="label">附件</text> | |
| 40 | + <view class="attach-list"> | |
| 41 | + <view v-for="(at, idx) in attachmentList" :key="idx" class="attach-item"> | |
| 42 | + <text class="attach-name">{{ at.name }}</text> | |
| 43 | + <text class="attach-view" @click.stop="onPreviewAttachment(at)">查看</text> | |
| 44 | + </view> | |
| 45 | + </view> | |
| 46 | + </view> | |
| 47 | + </view> | |
| 48 | + | |
| 49 | + <ProductRel mode="view" :list="lineList" /> | |
| 50 | + | |
| 51 | + <view v-if="form.specialAgreement" class="title-header"> | |
| 52 | + <image class="title-header_icon" src="/static/images/title.png" /> | |
| 53 | + <span>特殊约定</span> | |
| 54 | + </view> | |
| 55 | + <view v-if="form.specialAgreement" class="section"> | |
| 56 | + <text class="remark-text">{{ safeText(form.specialAgreement) }}</text> | |
| 57 | + </view> | |
| 58 | + </scroll-view> | |
| 59 | + </view> | |
| 60 | +</template> | |
| 61 | + | |
| 62 | +<script> | |
| 63 | +import ProductRel from './productRel.vue' | |
| 64 | +import { domesticAgreementDetailApi } from '@/api/procure-manage/domesticAgreement.js' | |
| 65 | +import { getDicByCodes, getDicName } from '@/utils/dic.js' | |
| 66 | + | |
| 67 | +export default { | |
| 68 | + name: 'DomesticAgreementViewer', | |
| 69 | + components: { ProductRel }, | |
| 70 | + props: { | |
| 71 | + id: { type: [String, Number], default: '' } | |
| 72 | + }, | |
| 73 | + data() { | |
| 74 | + return { | |
| 75 | + form: {}, | |
| 76 | + lineList: [], | |
| 77 | + attachmentList: [], | |
| 78 | + dicOptions: { | |
| 79 | + AUDIT_STATUS: [] | |
| 80 | + } | |
| 81 | + } | |
| 82 | + }, | |
| 83 | + computed: { | |
| 84 | + approvalStatusVisible() { | |
| 85 | + return !!(this.form && this.form.approvalStatus) | |
| 86 | + } | |
| 87 | + }, | |
| 88 | + created() { | |
| 89 | + this.loadDicData() | |
| 90 | + }, | |
| 91 | + watch: { | |
| 92 | + id: { | |
| 93 | + immediate: true, | |
| 94 | + handler(val) { | |
| 95 | + const v = (val !== undefined && val !== null) ? String(val) : '' | |
| 96 | + if (v) this.loadDetail(v) | |
| 97 | + } | |
| 98 | + } | |
| 99 | + }, | |
| 100 | + methods: { | |
| 101 | + async loadDicData() { | |
| 102 | + try { | |
| 103 | + const results = await getDicByCodes(['AUDIT_STATUS']) | |
| 104 | + this.dicOptions.AUDIT_STATUS = (results.AUDIT_STATUS && results.AUDIT_STATUS.data) || [] | |
| 105 | + } catch (e) { | |
| 106 | + this.dicOptions.AUDIT_STATUS = [] | |
| 107 | + } | |
| 108 | + }, | |
| 109 | + getAuditStatusText(status) { | |
| 110 | + const v = status == null ? '' : String(status) | |
| 111 | + if (!v) return '-' | |
| 112 | + return getDicName('AUDIT_STATUS', v, this.dicOptions.AUDIT_STATUS) || v | |
| 113 | + }, | |
| 114 | + safeText(v, def) { | |
| 115 | + const s = v == null ? '' : String(v) | |
| 116 | + if (s.trim()) return s | |
| 117 | + return def != null ? def : '-' | |
| 118 | + }, | |
| 119 | + formatDateOnly(v) { | |
| 120 | + const s = v == null ? '' : String(v).trim() | |
| 121 | + if (!s) return '-' | |
| 122 | + if (s.length >= 10) return s.slice(0, 10) | |
| 123 | + return s | |
| 124 | + }, | |
| 125 | + formatPercent(v) { | |
| 126 | + if (v === null || v === undefined || v === '') return '-' | |
| 127 | + const n = Number(v) | |
| 128 | + if (isNaN(n)) return String(v) | |
| 129 | + return n + '%' | |
| 130 | + }, | |
| 131 | + buildAttachmentList() { | |
| 132 | + const ids = this.form.attachmentFileIds | |
| 133 | + const names = this.form.attachmentFileNames | |
| 134 | + const idArr = (typeof ids === 'string' && ids) ? ids.split(',').filter(Boolean) : (Array.isArray(ids) ? ids : []) | |
| 135 | + const nameArr = (typeof names === 'string' && names) ? names.split(',').filter(Boolean) : (Array.isArray(names) ? names : []) | |
| 136 | + const len = Math.max(idArr.length, nameArr.length) | |
| 137 | + const list = [] | |
| 138 | + for (let i = 0; i < len; i++) { | |
| 139 | + list.push({ id: idArr[i] || '', name: nameArr[i] || ('附件' + (i + 1)) }) | |
| 140 | + } | |
| 141 | + this.attachmentList = list | |
| 142 | + }, | |
| 143 | + getFormValues() { | |
| 144 | + return JSON.parse(JSON.stringify(this.form || {})) | |
| 145 | + }, | |
| 146 | + checkForm() { | |
| 147 | + return true | |
| 148 | + }, | |
| 149 | + async loadDetail(id) { | |
| 150 | + try { | |
| 151 | + const res = await domesticAgreementDetailApi({ id: id }) | |
| 152 | + const data = res && res.data ? (res.data.data || res.data) : {} | |
| 153 | + this.form = Object.assign({}, data) | |
| 154 | + const lines = data && Array.isArray(data.procurementContractLineList) ? data.procurementContractLineList : [] | |
| 155 | + this.lineList = lines.map(l => Object.assign({}, l)) | |
| 156 | + this.buildAttachmentList() | |
| 157 | + } catch (e) { | |
| 158 | + this.form = {} | |
| 159 | + this.lineList = [] | |
| 160 | + this.attachmentList = [] | |
| 161 | + } | |
| 162 | + }, | |
| 163 | + onPreviewAttachment(at) { | |
| 164 | + if (!at || !at.id) { | |
| 165 | + uni.showToast({ title: '无法查看', icon: 'none' }) | |
| 166 | + return | |
| 167 | + } | |
| 168 | + uni.showToast({ title: '查看附件 ' + at.name, icon: 'none' }) | |
| 169 | + } | |
| 170 | + } | |
| 171 | +} | |
| 172 | +</script> | |
| 173 | + | |
| 174 | +<style lang="scss" scoped> | |
| 175 | +.detail-page { | |
| 176 | + background: #f3f3f3; | |
| 177 | +} | |
| 178 | +.scroll { | |
| 179 | + flex: 1; | |
| 180 | + padding: 8rpx 0 144rpx; | |
| 181 | +} | |
| 182 | +.title-header { | |
| 183 | + display: flex; | |
| 184 | + align-items: center; | |
| 185 | + padding: 24rpx 32rpx 12rpx; | |
| 186 | + background-color: #ffffff; | |
| 187 | + .title-header_icon { | |
| 188 | + width: 36rpx; | |
| 189 | + height: 36rpx; | |
| 190 | + margin-right: 12rpx; | |
| 191 | + } | |
| 192 | + span { | |
| 193 | + font-size: 34rpx; | |
| 194 | + font-weight: 600; | |
| 195 | + color: rgba(0, 0, 0, 0.9); | |
| 196 | + } | |
| 197 | +} | |
| 198 | +.section { | |
| 199 | + padding: 32rpx; | |
| 200 | + background: #fff; | |
| 201 | + margin-bottom: 20rpx; | |
| 202 | +} | |
| 203 | +.row { | |
| 204 | + display: flex; | |
| 205 | + margin-bottom: 28rpx; | |
| 206 | + &:last-child { margin-bottom: 0; } | |
| 207 | + &.company { | |
| 208 | + font-size: 36rpx; | |
| 209 | + font-weight: 600; | |
| 210 | + color: rgba(0, 0, 0, 0.9); | |
| 211 | + padding-top: 8rpx; | |
| 212 | + line-height: 50rpx; | |
| 213 | + } | |
| 214 | + .label { | |
| 215 | + max-width: 420rpx; | |
| 216 | + margin-right: 20rpx; | |
| 217 | + line-height: 32rpx; | |
| 218 | + font-size: 28rpx; | |
| 219 | + color: rgba(0, 0, 0, 0.6); | |
| 220 | + } | |
| 221 | + .value { | |
| 222 | + flex: 1; | |
| 223 | + line-height: 32rpx; | |
| 224 | + font-size: 28rpx; | |
| 225 | + color: rgba(0, 0, 0, 0.9); | |
| 226 | + text-align: right; | |
| 227 | + word-break: break-all; | |
| 228 | + } | |
| 229 | +} | |
| 230 | +.attach-list { | |
| 231 | + flex: 1; | |
| 232 | + display: flex; | |
| 233 | + flex-direction: column; | |
| 234 | + align-items: flex-end; | |
| 235 | + gap: 8rpx; | |
| 236 | +} | |
| 237 | +.attach-item { | |
| 238 | + display: flex; | |
| 239 | + align-items: center; | |
| 240 | + gap: 16rpx; | |
| 241 | + .attach-name { | |
| 242 | + font-size: 26rpx; | |
| 243 | + color: rgba(0, 0, 0, 0.9); | |
| 244 | + } | |
| 245 | + .attach-view { | |
| 246 | + font-size: 26rpx; | |
| 247 | + color: $theme-primary; | |
| 248 | + } | |
| 249 | +} | |
| 250 | +.remark-text { | |
| 251 | + font-size: 28rpx; | |
| 252 | + color: rgba(0, 0, 0, 0.9); | |
| 253 | + line-height: 1.6; | |
| 254 | + white-space: pre-wrap; | |
| 255 | +} | |
| 256 | +</style> | ... | ... |
pages/domestic-agreement/index.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <view class="page"> | |
| 3 | + <view class="agreement-list-fixed"> | |
| 4 | + <view class="search-row"> | |
| 5 | + <uni-search-bar | |
| 6 | + v-model="searchKeyword" | |
| 7 | + radius="6" | |
| 8 | + placeholder="请输入供方/需方名称或投诉编码" | |
| 9 | + clearButton="auto" | |
| 10 | + cancelButton="none" | |
| 11 | + bgColor="#F3F3F3" | |
| 12 | + textColor="rgba(0,0,0,0.4)" | |
| 13 | + @confirm="search" | |
| 14 | + @input="onSearchInput" | |
| 15 | + /> | |
| 16 | + <view class="tool-icons"> | |
| 17 | + <image class="tool-icon" src="/static/images/dev_manage/filter_icon.png" @click="openFilter" /> | |
| 18 | + </view> | |
| 19 | + </view> | |
| 20 | + | |
| 21 | + <view class="tabs"> | |
| 22 | + <view | |
| 23 | + v-for="(t, i) in tabs" | |
| 24 | + :key="i" | |
| 25 | + :class="['tab', { active: deleted === t.value }]" | |
| 26 | + @click="switchTab(t)" | |
| 27 | + > | |
| 28 | + {{ t.label }} | |
| 29 | + </view> | |
| 30 | + </view> | |
| 31 | + </view> | |
| 32 | + | |
| 33 | + <view class="list-box"> | |
| 34 | + <card-list | |
| 35 | + ref="cardRef" | |
| 36 | + :fetch-fn="fetchList" | |
| 37 | + :query="query" | |
| 38 | + :extra="extraParams" | |
| 39 | + row-key="id" | |
| 40 | + :enable-refresh="true" | |
| 41 | + :enable-load-more="true" | |
| 42 | + @loaded="onCardLoaded" | |
| 43 | + @error="onCardError" | |
| 44 | + > | |
| 45 | + <template v-slot="{ item }"> | |
| 46 | + <view class="card" @click="onCardClick(item)"> | |
| 47 | + <view class="card-header"> | |
| 48 | + <text class="title omit2">{{ item.procurementPlanCode || '-' }}</text> | |
| 49 | + <text :class="['status', `status_${item.approvalStatus}`]">{{ getAuditStatusText(item.approvalStatus) }}</text> | |
| 50 | + </view> | |
| 51 | + <view class="info-row"> | |
| 52 | + <text>供方</text> | |
| 53 | + <text>{{ item.supplierName || '-' }}</text> | |
| 54 | + </view> | |
| 55 | + <view class="info-row"> | |
| 56 | + <text>需方</text> | |
| 57 | + <text>{{ item.companyFullName || '-' }}</text> | |
| 58 | + </view> | |
| 59 | + <view class="info-row"> | |
| 60 | + <text>签订时间</text> | |
| 61 | + <text>{{ formatDateOnly(item.signTime) }}</text> | |
| 62 | + </view> | |
| 63 | + <view class="info-row"> | |
| 64 | + <text>发起人</text> | |
| 65 | + <text>{{ item.originatorName || '-' }}</text> | |
| 66 | + </view> | |
| 67 | + </view> | |
| 68 | + </template> | |
| 69 | + </card-list> | |
| 70 | + </view> | |
| 71 | + | |
| 72 | + <filter-modal | |
| 73 | + :visible.sync="filterVisible" | |
| 74 | + :value.sync="filterForm" | |
| 75 | + title="筛选" | |
| 76 | + @reset="onFilterReset" | |
| 77 | + @confirm="onFilterConfirm" | |
| 78 | + > | |
| 79 | + <template v-slot="{ model }"> | |
| 80 | + <view class="filter-form"> | |
| 81 | + <view class="form-item"> | |
| 82 | + <view class="label">供方</view> | |
| 83 | + <input class="input" v-model="model.supplierName" placeholder="请输入供应商名称" /> | |
| 84 | + </view> | |
| 85 | + <view class="form-item"> | |
| 86 | + <view class="label">需方</view> | |
| 87 | + <input class="input" v-model="model.companyFullName" placeholder="请输入公司名称(全称)" /> | |
| 88 | + </view> | |
| 89 | + <view class="form-item"> | |
| 90 | + <view class="label">投诉编码</view> | |
| 91 | + <input class="input" v-model="model.procurementPlanCode" placeholder="请输入计划单编号" /> | |
| 92 | + </view> | |
| 93 | + <view class="form-item"> | |
| 94 | + <view class="label">审核状态</view> | |
| 95 | + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'" | |
| 96 | + v-model="model.approvalStatus" @change="onApprovalStatusChange" :localdata="approvalStatusOptions" /> | |
| 97 | + </view> | |
| 98 | + <view class="form-item"> | |
| 99 | + <view class="label">签订时间</view> | |
| 100 | + <uni-datetime-picker type="daterange" v-model="model.signTimeRange" start="2023-01-01" /> | |
| 101 | + </view> | |
| 102 | + <view class="form-item"> | |
| 103 | + <view class="label">交货日期</view> | |
| 104 | + <uni-datetime-picker type="daterange" v-model="model.deliveryTimeRange" start="2023-01-01" /> | |
| 105 | + </view> | |
| 106 | + </view> | |
| 107 | + </template> | |
| 108 | + </filter-modal> | |
| 109 | + </view> | |
| 110 | +</template> | |
| 111 | + | |
| 112 | +<script> | |
| 113 | +import CardList from '@/components/card/index.vue' | |
| 114 | +import FilterModal from '@/components/filter/index.vue' | |
| 115 | +import { getDicByCodes, getDicName } from '@/utils/dic.js' | |
| 116 | +import { domesticAgreementQueryApi } from '@/api/procure-manage/domesticAgreement.js' | |
| 117 | + | |
| 118 | +export default { | |
| 119 | + name: 'DomesticAgreement', | |
| 120 | + components: { CardList, FilterModal }, | |
| 121 | + data() { | |
| 122 | + return { | |
| 123 | + searchKeyword: '', | |
| 124 | + searchKeywordDebounced: '', | |
| 125 | + searchDebounceTimer: null, | |
| 126 | + deleted: 0, | |
| 127 | + tabs: [ | |
| 128 | + { label: '有效合同', value: 0 }, | |
| 129 | + { label: '废除合同', value: 1 } | |
| 130 | + ], | |
| 131 | + query: { | |
| 132 | + supplierName: '', | |
| 133 | + companyFullName: '', | |
| 134 | + procurementPlanCode: '', | |
| 135 | + approvalStatus: '', | |
| 136 | + signTimeRange: [], | |
| 137 | + deliveryTimeRange: [] | |
| 138 | + }, | |
| 139 | + extraParams: {}, | |
| 140 | + currentItems: [], | |
| 141 | + filterVisible: false, | |
| 142 | + filterForm: { | |
| 143 | + supplierName: '', | |
| 144 | + companyFullName: '', | |
| 145 | + procurementPlanCode: '', | |
| 146 | + approvalStatus: '', | |
| 147 | + signTimeRange: [], | |
| 148 | + deliveryTimeRange: [] | |
| 149 | + }, | |
| 150 | + approvalStatusOptions: [ | |
| 151 | + { value: '', text: '全部' } | |
| 152 | + ], | |
| 153 | + dicOptions: { | |
| 154 | + AUDIT_STATUS: [] | |
| 155 | + } | |
| 156 | + } | |
| 157 | + }, | |
| 158 | + computed: { | |
| 159 | + extraCombined() { | |
| 160 | + const keyword = this.searchKeywordDebounced || '' | |
| 161 | + return { | |
| 162 | + keyword: keyword || undefined, | |
| 163 | + deleted: this.deleted | |
| 164 | + } | |
| 165 | + } | |
| 166 | + }, | |
| 167 | + watch: { | |
| 168 | + extraCombined: { | |
| 169 | + deep: true, | |
| 170 | + handler(v) { | |
| 171 | + this.extraParams = v | |
| 172 | + }, | |
| 173 | + immediate: true | |
| 174 | + } | |
| 175 | + }, | |
| 176 | + created() { | |
| 177 | + this.loadDicData() | |
| 178 | + }, | |
| 179 | + onShow() { | |
| 180 | + let needRefresh = '' | |
| 181 | + try { needRefresh = uni.getStorageSync('DOMESTIC_AGREEMENT_LIST_NEED_REFRESH') } catch (e) {} | |
| 182 | + if (!needRefresh) return | |
| 183 | + try { uni.removeStorageSync('DOMESTIC_AGREEMENT_LIST_NEED_REFRESH') } catch (e) {} | |
| 184 | + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.reload) { | |
| 185 | + this.$refs.cardRef.reload() | |
| 186 | + } | |
| 187 | + }, | |
| 188 | + onReachBottom() { | |
| 189 | + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) { | |
| 190 | + this.$refs.cardRef.onLoadMore() | |
| 191 | + } | |
| 192 | + }, | |
| 193 | + beforeDestroy() { | |
| 194 | + if (this.searchDebounceTimer) { | |
| 195 | + clearTimeout(this.searchDebounceTimer) | |
| 196 | + this.searchDebounceTimer = null | |
| 197 | + } | |
| 198 | + }, | |
| 199 | + methods: { | |
| 200 | + async loadDicData() { | |
| 201 | + try { | |
| 202 | + const results = await getDicByCodes(['AUDIT_STATUS']) | |
| 203 | + this.dicOptions.AUDIT_STATUS = (results.AUDIT_STATUS && results.AUDIT_STATUS.data) || [] | |
| 204 | + const list = Array.isArray(this.dicOptions.AUDIT_STATUS) ? this.dicOptions.AUDIT_STATUS : [] | |
| 205 | + this.approvalStatusOptions = [{ value: '', text: '全部' }].concat( | |
| 206 | + list.map(it => ({ value: it && it.code != null ? String(it.code) : '', text: it && it.name != null ? String(it.name) : '' })).filter(it => it.value) | |
| 207 | + ) | |
| 208 | + } catch (e) { | |
| 209 | + this.dicOptions.AUDIT_STATUS = [] | |
| 210 | + this.approvalStatusOptions = [{ value: '', text: '全部' }] | |
| 211 | + } | |
| 212 | + }, | |
| 213 | + getAuditStatusText(status) { | |
| 214 | + const v = status == null ? '' : String(status) | |
| 215 | + if (!v) return '-' | |
| 216 | + return getDicName('AUDIT_STATUS', v, this.dicOptions.AUDIT_STATUS) || v | |
| 217 | + }, | |
| 218 | + formatDateOnly(v) { | |
| 219 | + const s = v == null ? '' : String(v).trim() | |
| 220 | + if (!s) return '-' | |
| 221 | + if (s.length >= 10) return s.slice(0, 10) | |
| 222 | + return s | |
| 223 | + }, | |
| 224 | + onCardLoaded(_ref) { | |
| 225 | + var items = _ref.items | |
| 226 | + this.currentItems = items | |
| 227 | + }, | |
| 228 | + onCardError() { | |
| 229 | + uni.showToast({ title: '列表加载失败', icon: 'none' }) | |
| 230 | + }, | |
| 231 | + onSearchInput() { | |
| 232 | + var _this = this | |
| 233 | + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer) | |
| 234 | + this.searchDebounceTimer = setTimeout(function () { | |
| 235 | + _this.searchKeywordDebounced = _this.searchKeyword | |
| 236 | + _this.searchDebounceTimer = null | |
| 237 | + }, 1200) | |
| 238 | + }, | |
| 239 | + search(e) { | |
| 240 | + const val = e && e.value != null ? e.value : this.searchKeyword | |
| 241 | + this.searchKeyword = val | |
| 242 | + this.searchKeywordDebounced = val | |
| 243 | + }, | |
| 244 | + switchTab(t) { | |
| 245 | + this.deleted = t.value | |
| 246 | + }, | |
| 247 | + openFilter() { | |
| 248 | + this.filterForm = { | |
| 249 | + supplierName: this.query.supplierName || '', | |
| 250 | + companyFullName: this.query.companyFullName || '', | |
| 251 | + procurementPlanCode: this.query.procurementPlanCode || '', | |
| 252 | + approvalStatus: this.query.approvalStatus || '', | |
| 253 | + signTimeRange: Array.isArray(this.query.signTimeRange) ? this.query.signTimeRange.slice(0) : [], | |
| 254 | + deliveryTimeRange: Array.isArray(this.query.deliveryTimeRange) ? this.query.deliveryTimeRange.slice(0) : [] | |
| 255 | + } | |
| 256 | + this.filterVisible = true | |
| 257 | + }, | |
| 258 | + onFilterReset(payload) { | |
| 259 | + this.filterForm = payload | |
| 260 | + }, | |
| 261 | + onFilterConfirm(payload) { | |
| 262 | + this.query = { | |
| 263 | + supplierName: payload.supplierName || '', | |
| 264 | + companyFullName: payload.companyFullName || '', | |
| 265 | + procurementPlanCode: payload.procurementPlanCode || '', | |
| 266 | + approvalStatus: payload.approvalStatus || '', | |
| 267 | + signTimeRange: Array.isArray(payload.signTimeRange) ? payload.signTimeRange : [], | |
| 268 | + deliveryTimeRange: Array.isArray(payload.deliveryTimeRange) ? payload.deliveryTimeRange : [] | |
| 269 | + } | |
| 270 | + }, | |
| 271 | + onApprovalStatusChange(e) { | |
| 272 | + const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ? e.value : '') | |
| 273 | + this.filterForm.approvalStatus = raw | |
| 274 | + }, | |
| 275 | + fetchList(_ref2) { | |
| 276 | + var _this2 = this | |
| 277 | + var pageIndex = _ref2.pageIndex | |
| 278 | + var pageSize = _ref2.pageSize | |
| 279 | + var query = _ref2.query | |
| 280 | + var extra = _ref2.extra | |
| 281 | + const q = query || {} | |
| 282 | + const e = extra || {} | |
| 283 | + const signRange = Array.isArray(q.signTimeRange) ? q.signTimeRange : [] | |
| 284 | + const deliveryRange = Array.isArray(q.deliveryTimeRange) ? q.deliveryTimeRange : [] | |
| 285 | + const keyword = e.keyword || '' | |
| 286 | + const params = { | |
| 287 | + pageIndex: pageIndex, | |
| 288 | + pageSize: pageSize, | |
| 289 | + deleted: e.deleted != null ? e.deleted : 0, | |
| 290 | + supplierName: q.supplierName || '', | |
| 291 | + companyFullName: q.companyFullName || '', | |
| 292 | + procurementPlanCode: q.procurementPlanCode || '', | |
| 293 | + approvalStatus: q.approvalStatus || '', | |
| 294 | + startSignTime: signRange && signRange.length === 2 ? signRange[0] : '', | |
| 295 | + endSignTime: signRange && signRange.length === 2 ? signRange[1] : '', | |
| 296 | + startDeliveryTime: deliveryRange && deliveryRange.length === 2 ? deliveryRange[0] : '', | |
| 297 | + endDeliveryTime: deliveryRange && deliveryRange.length === 2 ? deliveryRange[1] : '' | |
| 298 | + } | |
| 299 | + if (keyword) { | |
| 300 | + if (!params.supplierName) params.supplierName = keyword | |
| 301 | + if (!params.companyFullName) params.companyFullName = keyword | |
| 302 | + if (!params.procurementPlanCode) params.procurementPlanCode = keyword | |
| 303 | + } | |
| 304 | + return domesticAgreementQueryApi(params).then(function (res) { | |
| 305 | + const _data = res && res.data ? res.data : {} | |
| 306 | + let records = _data.datas || _data.list || _data.records || [] | |
| 307 | + const totalCount = _data.totalCount || _data.count || 0 | |
| 308 | + const hasNext = _data.hasNext || false | |
| 309 | + records = records.map(function (it) { return Object.assign({}, it) }) | |
| 310 | + return { records: records, totalCount: totalCount, hasNext: hasNext } | |
| 311 | + }).catch(function () { | |
| 312 | + _this2.onCardError() | |
| 313 | + return { records: [], totalCount: 0, hasNext: false } | |
| 314 | + }) | |
| 315 | + }, | |
| 316 | + onCardClick(item) { | |
| 317 | + const id = item && (item.id || item.itemId) | |
| 318 | + if (!id) { | |
| 319 | + uni.showToast({ title: '缺少ID', icon: 'none' }) | |
| 320 | + return | |
| 321 | + } | |
| 322 | + uni.navigateTo({ url: '/pages/domestic-agreement/detail?id=' + id }) | |
| 323 | + } | |
| 324 | + } | |
| 325 | +} | |
| 326 | +</script> | |
| 327 | + | |
| 328 | +<style lang="scss" scoped> | |
| 329 | +.page { | |
| 330 | + display: flex; | |
| 331 | + flex-direction: column; | |
| 332 | + height: 100vh; | |
| 333 | +} | |
| 334 | +.agreement-list-fixed { | |
| 335 | + position: fixed; | |
| 336 | + top: 96rpx; | |
| 337 | + left: 0; | |
| 338 | + right: 0; | |
| 339 | + z-index: 2; | |
| 340 | + background: #fff; | |
| 341 | + .search-row { | |
| 342 | + display: flex; | |
| 343 | + align-items: center; | |
| 344 | + padding: 16rpx 32rpx; | |
| 345 | + .uni-searchbar { padding: 0; flex: 1; } | |
| 346 | + .tool-icons { | |
| 347 | + display: flex; | |
| 348 | + .tool-icon { width: 48rpx; height: 48rpx; display: block; margin-left: 32rpx; } | |
| 349 | + } | |
| 350 | + } | |
| 351 | + .tabs { | |
| 352 | + display: flex; | |
| 353 | + align-items: center; | |
| 354 | + justify-content: space-between; | |
| 355 | + padding: 26rpx 34rpx; | |
| 356 | + border-bottom: solid 1px #E7E7E7; | |
| 357 | + .tab { width: 50%; text-align: center; color: rgba(0,0,0,0.9); line-height: 44rpx; position: relative; font-weight: 600; } | |
| 358 | + .tab.active { color: $theme-primary; } | |
| 359 | + .tab.active::after { | |
| 360 | + content: ''; | |
| 361 | + position: absolute; | |
| 362 | + left: 50%; | |
| 363 | + transform: translateX(-50%); | |
| 364 | + bottom: -13px; | |
| 365 | + width: 32rpx; | |
| 366 | + height: 6rpx; | |
| 367 | + border-radius: 4rpx; | |
| 368 | + background: $theme-primary; | |
| 369 | + } | |
| 370 | + } | |
| 371 | +} | |
| 372 | +::v-deep .uni-searchbar__box { height: 80rpx !important; justify-content: start; .uni-searchbar__box-search-input { font-size: 32rpx !important; } } | |
| 373 | +.list-box { | |
| 374 | + flex: 1; | |
| 375 | + padding-top: 236rpx; | |
| 376 | + .card { position: relative; } | |
| 377 | + .card-header { | |
| 378 | + margin-bottom: 28rpx; | |
| 379 | + position: relative; | |
| 380 | + .title { font-size: 36rpx; font-weight: 600; line-height: 50rpx; color: rgba(0,0,0,0.9); width: 578rpx; } | |
| 381 | + .status { | |
| 382 | + position: absolute; | |
| 383 | + top: -32rpx; | |
| 384 | + right: -12rpx; | |
| 385 | + height: 48rpx; | |
| 386 | + line-height: 48rpx; | |
| 387 | + font-weight: 600; | |
| 388 | + color: #fff; | |
| 389 | + font-size: 24rpx; | |
| 390 | + padding: 0 14rpx; | |
| 391 | + border-radius: 6rpx; | |
| 392 | + box-sizing: content-box; | |
| 393 | + | |
| 394 | + &.status_AUDIT { | |
| 395 | + background: $theme-primary; | |
| 396 | + } | |
| 397 | + | |
| 398 | + &.status_PASS { | |
| 399 | + background: #2BA471; | |
| 400 | + } | |
| 401 | + | |
| 402 | + &.status_REFUSE { | |
| 403 | + background: #D54941; | |
| 404 | + } | |
| 405 | + | |
| 406 | + &.status_CANCEL { | |
| 407 | + background: #E7E7E7; | |
| 408 | + color: rgba(0, 0, 0, 0.9); | |
| 409 | + } | |
| 410 | + } | |
| 411 | + } | |
| 412 | + .info-row { | |
| 413 | + display: flex; | |
| 414 | + align-items: center; | |
| 415 | + color: rgba(0,0,0,0.6); | |
| 416 | + font-size: 28rpx; | |
| 417 | + margin-bottom: 24rpx; | |
| 418 | + height: 32rpx; | |
| 419 | + &:last-child { margin-bottom: 0; } | |
| 420 | + text { | |
| 421 | + width: 50%; | |
| 422 | + &:last-child { color: rgba(0,0,0,0.9); width: 50%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } | |
| 423 | + } | |
| 424 | + } | |
| 425 | +} | |
| 426 | +.filter-form { | |
| 427 | + .form-item { margin-bottom: 24rpx; } | |
| 428 | + .label { margin-bottom: 20rpx; color: rgba(0,0,0,0.9); height: 44rpx; line-height: 44rpx; font-size: 30rpx; } | |
| 429 | + .input { | |
| 430 | + width: 100%; | |
| 431 | + height: 72rpx; | |
| 432 | + line-height: 72rpx; | |
| 433 | + padding: 0 24rpx; | |
| 434 | + border: 1rpx solid #E7E7E7; | |
| 435 | + border-radius: 8rpx; | |
| 436 | + font-size: 28rpx; | |
| 437 | + color: rgba(0,0,0,0.9); | |
| 438 | + background: #fff; | |
| 439 | + box-sizing: border-box; | |
| 440 | + } | |
| 441 | +} | |
| 442 | +</style> | ... | ... |
pages/domestic-agreement/modify.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.procurementPlanCode) }}</text> | |
| 7 | + <view class="row"> | |
| 8 | + <text class="label">供方</text> | |
| 9 | + <text class="value">{{ safeText(form.supplierName) }}</text> | |
| 10 | + </view> | |
| 11 | + <view class="row"> | |
| 12 | + <text class="label">需方</text> | |
| 13 | + <text class="value">{{ safeText(form.companyFullName) }}</text> | |
| 14 | + </view> | |
| 15 | + <view class="row"> | |
| 16 | + <text class="label">签订地点</text> | |
| 17 | + <text class="value">{{ safeText(form.signPlace, '芜湖市') }}</text> | |
| 18 | + </view> | |
| 19 | + <view class="row"> | |
| 20 | + <text class="label">签订时间</text> | |
| 21 | + <text class="value">{{ formatDateOnly(form.signTime) }}</text> | |
| 22 | + </view> | |
| 23 | + <view class="row"> | |
| 24 | + <text class="label">投诉编码</text> | |
| 25 | + <text class="value">{{ safeText(form.procurementPlanCode) }}</text> | |
| 26 | + </view> | |
| 27 | + <view class="row"> | |
| 28 | + <text class="label">结算比例</text> | |
| 29 | + <text class="value">{{ formatPercent(form.settlementRatio) }}</text> | |
| 30 | + </view> | |
| 31 | + <view v-if="form.createUserName" class="row"> | |
| 32 | + <text class="label">发起人</text> | |
| 33 | + <text class="value">{{ safeText(form.createUserName) }}</text> | |
| 34 | + </view> | |
| 35 | + <view v-if="approvalStatusVisible" class="row"> | |
| 36 | + <text class="label">审核状态</text> | |
| 37 | + <text class="value">{{ getAuditStatusText(form.approvalStatus) }}</text> | |
| 38 | + </view> | |
| 39 | + </view> | |
| 40 | + | |
| 41 | + <ProductRel mode="view" :list="lineList" /> | |
| 42 | + | |
| 43 | + <view class="title-header"> | |
| 44 | + <image class="title-header_icon" src="/static/images/title.png" /> | |
| 45 | + <span>特殊约定</span> | |
| 46 | + </view> | |
| 47 | + <view class="section"> | |
| 48 | + <textarea v-model="form.specialAgreement" class="remark-text" placeholder="请输入特殊约定" /> | |
| 49 | + </view> | |
| 50 | + <view class="section"> | |
| 51 | + <text class="section-title">附件上传:</text> | |
| 52 | + <view class="attach-box"> | |
| 53 | + <view v-for="(f, idx) in attachmentFiles" :key="idx" class="attach-row"> | |
| 54 | + <FileUpload :value="f" @input="onAttachmentInput(idx, $event)" /> | |
| 55 | + <text class="attach-del" @click.stop="removeAttachment(idx)">删除</text> | |
| 56 | + </view> | |
| 57 | + <view class="attach-row"> | |
| 58 | + <FileUpload :value="newAttachment" @input="onAddAttachment" /> | |
| 59 | + </view> | |
| 60 | + </view> | |
| 61 | + </view> | |
| 62 | + </view> | |
| 63 | + </scroll-view> | |
| 64 | + <view class="footer"> | |
| 65 | + <button class="btn cancel" @click="onCancelEdit">取消</button> | |
| 66 | + <button class="btn submit" type="primary" :disabled="submitting" @click="onSave">{{ submitting ? '保存中...' : '保存' }}</button> | |
| 67 | + </view> | |
| 68 | + </view> | |
| 69 | +</template> | |
| 70 | + | |
| 71 | +<script> | |
| 72 | +import DetailButtons from '@/components/detail-buttons/index.vue' | |
| 73 | +import ProductRel from './productRel.vue' | |
| 74 | +import FileUpload from '@/components/file-upload/index.vue' | |
| 75 | +import { getInfo } from '@/api/login' | |
| 76 | +import { domesticAgreementCancelApi, domesticAgreementDetailApi, domesticAgreementSubmitApi, domesticAgreementEditApi } from '@/api/procure-manage/domesticAgreement.js' | |
| 77 | +import { getDicByCodes, getDicName } from '@/utils/dic.js' | |
| 78 | + | |
| 79 | +export default { | |
| 80 | + name: 'DomesticAgreementModify', | |
| 81 | + components: { DetailButtons, ProductRel, FileUpload }, | |
| 82 | + data() { | |
| 83 | + return { | |
| 84 | + id: '', | |
| 85 | + submitting: false, | |
| 86 | + rawDetail: {}, | |
| 87 | + form: { | |
| 88 | + id: '', | |
| 89 | + procurementPlanId: '', | |
| 90 | + procurementPlanCode: '', | |
| 91 | + supplierId: '', | |
| 92 | + supplierName: '', | |
| 93 | + companyShortId: '', | |
| 94 | + companyFullName: '', | |
| 95 | + signPlace: '', | |
| 96 | + signTime: '', | |
| 97 | + deliveryTime: '', | |
| 98 | + settlementRatio: '', | |
| 99 | + specialAgreement: '', | |
| 100 | + attachmentFileIds: '', | |
| 101 | + attachmentFileNames: '', | |
| 102 | + createUserName: '', | |
| 103 | + createById: '', | |
| 104 | + approvalStatus: '' | |
| 105 | + }, | |
| 106 | + lineList: [], | |
| 107 | + attachmentFiles: [], | |
| 108 | + newAttachment: { id: '', name: '' }, | |
| 109 | + dicOptions: { | |
| 110 | + AUDIT_STATUS: [] | |
| 111 | + }, | |
| 112 | + buttons: [{ | |
| 113 | + text: '审核详情', | |
| 114 | + visible: true, | |
| 115 | + variant: 'outline', | |
| 116 | + event: 'auditDetail', | |
| 117 | + },{ | |
| 118 | + text: '审核', | |
| 119 | + visible: true, | |
| 120 | + variant: 'primary', | |
| 121 | + event: 'audit', | |
| 122 | + },{ | |
| 123 | + text: '编辑', | |
| 124 | + visible: true, | |
| 125 | + variant: 'outline', | |
| 126 | + event: 'edit', | |
| 127 | + }, | |
| 128 | + { | |
| 129 | + text: '提交审核', | |
| 130 | + visible: true, | |
| 131 | + variant: 'outline', | |
| 132 | + event: 'submitAudit', | |
| 133 | + }, | |
| 134 | + { | |
| 135 | + text: '取消', | |
| 136 | + visible: true, | |
| 137 | + variant: 'outline', | |
| 138 | + event: 'cancel', | |
| 139 | + }], | |
| 140 | + currentUserId: '', | |
| 141 | + } | |
| 142 | + }, | |
| 143 | + computed: { | |
| 144 | + displayButtons() { | |
| 145 | + const row = this.form || {} | |
| 146 | + const status = row.approvalStatus | |
| 147 | + const isDraft = !status; //草稿 | |
| 148 | + const isAudit = status === 'AUDIT'; | |
| 149 | + const isPass = status === 'PASS'; | |
| 150 | + const isRefuse = status === 'REFUSE'; | |
| 151 | + return [ | |
| 152 | + { ...this.buttons[0], visible: (isAudit || isPass)&& this.form?.showExamineDetail === true && this.$auth.hasPermi('agreement-manage:domestic-agreement:view') }, | |
| 153 | + { ...this.buttons[1], visible: isAudit && this.form?.showExamine === true && this.$auth.hasPermi('agreement-manage:domestic-agreement:approve') }, | |
| 154 | + { ...this.buttons[2], visible: (isDraft || isRefuse)&&this.form.createById === this.currentUserId && this.$auth.hasPermi('agreement-manage:domestic-agreement:modify') }, | |
| 155 | + { ...this.buttons[3], visible: (isDraft || isRefuse) && row.createById === this.currentUserId&& this.$auth.hasPermi('agreement-manage:domestic-agreement:submit') }, | |
| 156 | + { ...this.buttons[4], visible:(isRefuse || !status) && this.currentUserId === row?.createById && this.$auth.hasPermi('agreement-manage:domestic-agreement:cancel') }, | |
| 157 | + ] | |
| 158 | + }, | |
| 159 | + approvalStatusVisible() { | |
| 160 | + return !!(this.form && this.form.approvalStatus) | |
| 161 | + } | |
| 162 | + }, | |
| 163 | + onLoad(query) { | |
| 164 | + this.id = (query && query.id) || '' | |
| 165 | + this.loadDicData() | |
| 166 | + this.loadDetail() | |
| 167 | + this.getUserInfo() | |
| 168 | + }, | |
| 169 | + onShow() { | |
| 170 | + let needRefresh = '' | |
| 171 | + try { needRefresh = uni.getStorageSync('DOMESTIC_AGREEMENT_DETAIL_NEED_REFRESH') } catch (e) {} | |
| 172 | + if (!needRefresh) return | |
| 173 | + try { uni.removeStorageSync('DOMESTIC_AGREEMENT_DETAIL_NEED_REFRESH') } catch (e) {} | |
| 174 | + this.loadDetail() | |
| 175 | + }, | |
| 176 | + methods: { | |
| 177 | + handleButtonClick(btn) { | |
| 178 | + if (!btn || btn.disabled) return | |
| 179 | + var e = btn.event || '' | |
| 180 | + if (e === 'cancel') return this.onCancel() | |
| 181 | + if (e === 'submitAudit') return this.onSubmitAudit() | |
| 182 | + uni.showToast({ title: (btn.text || '操作') + '待实现', icon: 'none' }) | |
| 183 | + }, | |
| 184 | + refreshListFlags() { | |
| 185 | + try { uni.setStorageSync('DOMESTIC_AGREEMENT_LIST_NEED_REFRESH', '1') } catch (e) {} | |
| 186 | + try { uni.setStorageSync('DOMESTIC_AGREEMENT_DETAIL_NEED_REFRESH', '1') } catch (e) {} | |
| 187 | + }, | |
| 188 | + runWithConfirm(opts) { | |
| 189 | + var self = this | |
| 190 | + var title = opts.title || '提示' | |
| 191 | + var content = opts.content || '' | |
| 192 | + var run = opts.run | |
| 193 | + var loading = opts.loading || '处理中' | |
| 194 | + var successText = opts.successText || '操作成功' | |
| 195 | + var failText = opts.failText || '操作失败' | |
| 196 | + if (!this.id) { | |
| 197 | + uni.showToast({ title: '缺少合同ID', icon: 'none' }) | |
| 198 | + return | |
| 199 | + } | |
| 200 | + var apiFn = function () { | |
| 201 | + uni.showLoading({ title: loading, mask: true }) | |
| 202 | + Promise.resolve(run(self.id)).then(function () { | |
| 203 | + uni.hideLoading() | |
| 204 | + uni.showToast({ title: successText, icon: 'none' }) | |
| 205 | + self.refreshListFlags() | |
| 206 | + self.loadDetail() | |
| 207 | + }).catch(function (e) { | |
| 208 | + uni.hideLoading() | |
| 209 | + uni.showToast({ title: (e && (e.msg || e.message)) ? (e.msg || e.message) : failText, icon: 'none' }) | |
| 210 | + }) | |
| 211 | + } | |
| 212 | + uni.showModal({ | |
| 213 | + title: title, | |
| 214 | + content: content, | |
| 215 | + confirmText: '确定', | |
| 216 | + cancelText: '取消', | |
| 217 | + success: function (res) { | |
| 218 | + if (!res || !res.confirm) return | |
| 219 | + apiFn() | |
| 220 | + } | |
| 221 | + }) | |
| 222 | + }, | |
| 223 | + onCancel() { | |
| 224 | + this.runWithConfirm({ | |
| 225 | + title: '取消', | |
| 226 | + content: '确认取消该合同吗?', | |
| 227 | + loading: '提交中', | |
| 228 | + successText: '取消成功', | |
| 229 | + failText: '取消失败', | |
| 230 | + run: function (id) { return domesticAgreementCancelApi(id) } | |
| 231 | + }) | |
| 232 | + }, | |
| 233 | + onSubmitAudit() { | |
| 234 | + this.runWithConfirm({ | |
| 235 | + title: '提交审核', | |
| 236 | + content: '确认提交审核吗?', | |
| 237 | + loading: '提交中', | |
| 238 | + successText: '提交成功', | |
| 239 | + failText: '提交审核失败', | |
| 240 | + run: function (id) { return domesticAgreementSubmitApi(id) } | |
| 241 | + }) | |
| 242 | + }, | |
| 243 | + onCancelEdit() { | |
| 244 | + uni.navigateTo({ url: '/pages/domestic-agreement/detail?id=' + this.id }) | |
| 245 | + }, | |
| 246 | + async getUserInfo() { | |
| 247 | + try { | |
| 248 | + var res = await getInfo() | |
| 249 | + this.currentUserId = (res && res.id) ? res.id : '' | |
| 250 | + } catch (e) { | |
| 251 | + this.currentUserId = '' | |
| 252 | + } | |
| 253 | + }, | |
| 254 | + async loadDicData() { | |
| 255 | + try { | |
| 256 | + const results = await getDicByCodes(['AUDIT_STATUS']) | |
| 257 | + this.dicOptions.AUDIT_STATUS = (results.AUDIT_STATUS && results.AUDIT_STATUS.data) || [] | |
| 258 | + } catch (e) { | |
| 259 | + this.dicOptions.AUDIT_STATUS = [] | |
| 260 | + } | |
| 261 | + }, | |
| 262 | + getAuditStatusText(status) { | |
| 263 | + const v = status == null ? '' : String(status) | |
| 264 | + if (!v) return '-' | |
| 265 | + return getDicName('AUDIT_STATUS', v, this.dicOptions.AUDIT_STATUS) || v | |
| 266 | + }, | |
| 267 | + loadDetail() { | |
| 268 | + if (!this.id) { | |
| 269 | + uni.showToast({ title: '缺少合同ID', icon: 'none' }) | |
| 270 | + return | |
| 271 | + } | |
| 272 | + uni.showLoading && uni.showLoading({ title: '加载中...', mask: true }) | |
| 273 | + this.fetchDetail({ id: this.id }) | |
| 274 | + .then(res => { | |
| 275 | + const data = res && res.data ? (res.data.data || res.data) : {} | |
| 276 | + this.rawDetail = Object.assign({}, data) | |
| 277 | + this.form = Object.assign({}, this.form, data) | |
| 278 | + const lines = data && Array.isArray(data.procurementContractLineList) ? data.procurementContractLineList : [] | |
| 279 | + this.lineList = lines.map(l => Object.assign({}, l)) | |
| 280 | + this.buildAttachmentFiles() | |
| 281 | + this.notifyListRefresh() | |
| 282 | + }) | |
| 283 | + .catch(() => { | |
| 284 | + uni.showToast({ title: '详情加载失败', icon: 'none' }) | |
| 285 | + }) | |
| 286 | + .finally(() => { | |
| 287 | + uni.hideLoading && uni.hideLoading() | |
| 288 | + }) | |
| 289 | + }, | |
| 290 | + fetchDetail(params) { | |
| 291 | + const self = this | |
| 292 | + return domesticAgreementDetailApi(params).catch(function () { | |
| 293 | + return self.mockDetail(params) | |
| 294 | + }) | |
| 295 | + }, | |
| 296 | + mockDetail(params) { | |
| 297 | + return new Promise(resolve => { | |
| 298 | + const mock = { | |
| 299 | + id: params.id, | |
| 300 | + procurementPlanId: 'plan-' + params.id, | |
| 301 | + procurementPlanCode: 'NMHT2026000' + params.id, | |
| 302 | + supplierId: 'S001', | |
| 303 | + supplierName: '上海钢材贸易有限公司', | |
| 304 | + companyShortId: 'C001', | |
| 305 | + companyFullName: '北京远大集团有限公司', | |
| 306 | + signPlace: '芜湖市', | |
| 307 | + signTime: '2026-08-15', | |
| 308 | + deliveryTime: '2026-09-20', | |
| 309 | + settlementRatio: 80, | |
| 310 | + specialAgreement: '1. 本合同项下货物质量须符合国标及双方约定的技术标准;\n2. 如出现质量问题,供方须在3个工作日内响应处理;\n3. 价格波动超过±5%时,双方另行协商结算。', | |
| 311 | + attachmentFileIds: 'f1,f2', | |
| 312 | + attachmentFileNames: '内贸合同扫描件.pdf,补充条款.docx', | |
| 313 | + createUserName: '张三', | |
| 314 | + approvalStatus: 'AUDIT', | |
| 315 | + procurementContractLineList: [ | |
| 316 | + { | |
| 317 | + id: 'L1', | |
| 318 | + contractId: params.id, | |
| 319 | + itemId: 'I1', | |
| 320 | + planLineId: 'PL1', | |
| 321 | + invoiceProductName: '废铜', | |
| 322 | + productId: 'P001', | |
| 323 | + productName: '光亮铜', | |
| 324 | + quantity: '25.500', | |
| 325 | + unitPrice: '62500.00', | |
| 326 | + deliveryTime: '2026-09-15' | |
| 327 | + }, | |
| 328 | + { | |
| 329 | + id: 'L2', | |
| 330 | + contractId: params.id, | |
| 331 | + itemId: 'I2', | |
| 332 | + planLineId: 'PL2', | |
| 333 | + invoiceProductName: '废铜', | |
| 334 | + productId: 'P002', | |
| 335 | + productName: '一特铜', | |
| 336 | + quantity: '18.200', | |
| 337 | + unitPrice: '61800.00', | |
| 338 | + deliveryTime: '2026-09-20' | |
| 339 | + }, | |
| 340 | + { | |
| 341 | + id: 'L3', | |
| 342 | + contractId: params.id, | |
| 343 | + itemId: 'I3', | |
| 344 | + planLineId: 'PL3', | |
| 345 | + invoiceProductName: '废铝', | |
| 346 | + productId: 'P003', | |
| 347 | + productName: '高纯铝锭', | |
| 348 | + quantity: '42.000', | |
| 349 | + unitPrice: '19800.00', | |
| 350 | + deliveryTime: '2026-09-25' | |
| 351 | + } | |
| 352 | + ] | |
| 353 | + } | |
| 354 | + setTimeout(() => resolve({ data: { data: mock } }), 200) | |
| 355 | + }) | |
| 356 | + }, | |
| 357 | + buildAttachmentFiles() { | |
| 358 | + const ids = this.form.attachmentFileIds | |
| 359 | + const names = this.form.attachmentFileNames | |
| 360 | + const idArr = (typeof ids === 'string' && ids) ? ids.split(',').filter(Boolean) : (Array.isArray(ids) ? ids : []) | |
| 361 | + const nameArr = (typeof names === 'string' && names) ? names.split(',').filter(Boolean) : (Array.isArray(names) ? names : []) | |
| 362 | + const len = Math.max(idArr.length, nameArr.length) | |
| 363 | + const list = [] | |
| 364 | + for (let i = 0; i < len; i++) { | |
| 365 | + list.push({ id: idArr[i] || '', name: nameArr[i] || ('附件' + (i + 1)) }) | |
| 366 | + } | |
| 367 | + this.attachmentFiles = list | |
| 368 | + }, | |
| 369 | + syncAttachmentToForm() { | |
| 370 | + const list = Array.isArray(this.attachmentFiles) ? this.attachmentFiles : [] | |
| 371 | + const ids = list.map(f => (f && f.id) ? String(f.id) : '').filter(Boolean) | |
| 372 | + const names = list.map(f => (f && f.name) ? String(f.name) : '').filter(Boolean) | |
| 373 | + this.form.attachmentFileIds = ids.join(',') | |
| 374 | + this.form.attachmentFileNames = names.join(',') | |
| 375 | + }, | |
| 376 | + removeAttachment(idx) { | |
| 377 | + const list = Array.isArray(this.attachmentFiles) ? this.attachmentFiles.slice(0) : [] | |
| 378 | + list.splice(idx, 1) | |
| 379 | + this.attachmentFiles = list | |
| 380 | + }, | |
| 381 | + onAddAttachment(val) { | |
| 382 | + const payload = val || { id: '', name: '' } | |
| 383 | + if (!payload.id) return | |
| 384 | + const list = Array.isArray(this.attachmentFiles) ? this.attachmentFiles.slice(0) : [] | |
| 385 | + list.push(payload) | |
| 386 | + this.attachmentFiles = list | |
| 387 | + this.newAttachment = { id: '', name: '' } | |
| 388 | + }, | |
| 389 | + onAttachmentInput(idx, val) { | |
| 390 | + const list = Array.isArray(this.attachmentFiles) ? this.attachmentFiles.slice(0) : [] | |
| 391 | + list[idx] = val || { id: '', name: '' } | |
| 392 | + this.attachmentFiles = list | |
| 393 | + }, | |
| 394 | + onLineListInput(list) { | |
| 395 | + this.lineList = Array.isArray(list) ? list.slice(0) : [] | |
| 396 | + }, | |
| 397 | + buildPayload() { | |
| 398 | + this.syncAttachmentToForm() | |
| 399 | + const f = this.form || {} | |
| 400 | + const cleanedLines = (this.lineList || []).map(line => { | |
| 401 | + const l = Object.assign({}, line) | |
| 402 | + delete l._key | |
| 403 | + delete l.fixedLossRate | |
| 404 | + delete l.collapsed | |
| 405 | + return l | |
| 406 | + }) | |
| 407 | + const payload = Object.assign({}, this.rawDetail, f, { | |
| 408 | + id: f.id || this.id || '', | |
| 409 | + procurementContractLineList: cleanedLines, | |
| 410 | + attachmentFileIds: f.attachmentFileIds || '', | |
| 411 | + attachmentFileNames: f.attachmentFileNames || '' | |
| 412 | + }) | |
| 413 | + delete payload.showExamine | |
| 414 | + delete payload.showExamineDetail | |
| 415 | + return payload | |
| 416 | + }, | |
| 417 | + onSave() { | |
| 418 | + if (this.submitting) return | |
| 419 | + this.submitting = true | |
| 420 | + const payload = this.buildPayload() | |
| 421 | + uni.showLoading({ title: '保存中...', mask: true }) | |
| 422 | + domesticAgreementEditApi(payload) | |
| 423 | + .then(() => { | |
| 424 | + uni.hideLoading() | |
| 425 | + uni.showToast({ title: '保存成功', icon: 'none' }) | |
| 426 | + this.refreshListFlags() | |
| 427 | + setTimeout(() => { | |
| 428 | + uni.navigateTo({ url: '/pages/domestic-agreement/detail?id=' + this.id }) | |
| 429 | + }, 800) | |
| 430 | + }) | |
| 431 | + .catch((e) => { | |
| 432 | + uni.hideLoading() | |
| 433 | + uni.showToast({ title: (e && (e.msg || e.message)) ? (e.msg || e.message) : '保存失败', icon: 'none' }) | |
| 434 | + }) | |
| 435 | + .finally(() => { | |
| 436 | + this.submitting = false | |
| 437 | + }) | |
| 438 | + }, | |
| 439 | + notifyListRefresh() { | |
| 440 | + try { uni.setStorageSync('DOMESTIC_AGREEMENT_LIST_NEED_REFRESH', '1') } catch (e) {} | |
| 441 | + }, | |
| 442 | + safeText(v, def) { | |
| 443 | + const s = v == null ? '' : String(v) | |
| 444 | + if (s.trim()) return s | |
| 445 | + return def != null ? def : '-' | |
| 446 | + }, | |
| 447 | + formatDateOnly(v) { | |
| 448 | + const s = v == null ? '' : String(v).trim() | |
| 449 | + if (!s) return '-' | |
| 450 | + if (s.length >= 10) return s.slice(0, 10) | |
| 451 | + return s | |
| 452 | + }, | |
| 453 | + formatPercent(v) { | |
| 454 | + if (v === null || v === undefined || v === '') return '-' | |
| 455 | + const n = Number(v) | |
| 456 | + if (isNaN(n)) return String(v) | |
| 457 | + return n + '%' | |
| 458 | + } | |
| 459 | + } | |
| 460 | +} | |
| 461 | +</script> | |
| 462 | + | |
| 463 | +<style lang="scss" scoped> | |
| 464 | +.page { | |
| 465 | + display: flex; | |
| 466 | + flex-direction: column; | |
| 467 | + height: 100%; | |
| 468 | +} | |
| 469 | +.scroll { | |
| 470 | + flex: 1; | |
| 471 | + padding: 8rpx 0 144rpx; | |
| 472 | +} | |
| 473 | +.detail-page { | |
| 474 | + background: #f3f3f3; | |
| 475 | +} | |
| 476 | +.title-header { | |
| 477 | + display: flex; | |
| 478 | + align-items: center; | |
| 479 | + padding: 24rpx 32rpx 12rpx; | |
| 480 | + background-color: #ffffff; | |
| 481 | + .title-header_icon { | |
| 482 | + width: 36rpx; | |
| 483 | + height: 36rpx; | |
| 484 | + margin-right: 12rpx; | |
| 485 | + } | |
| 486 | + span { | |
| 487 | + font-size: 34rpx; | |
| 488 | + font-weight: 600; | |
| 489 | + color: rgba(0, 0, 0, 0.9); | |
| 490 | + } | |
| 491 | +} | |
| 492 | +.section { | |
| 493 | + padding: 32rpx; | |
| 494 | + background: #fff; | |
| 495 | + margin-bottom: 20rpx; | |
| 496 | +} | |
| 497 | +.section-title { | |
| 498 | + font-size: 28rpx; | |
| 499 | + color: rgba(0, 0, 0, 0.9); | |
| 500 | + font-weight: 600; | |
| 501 | + display: block; | |
| 502 | + margin-bottom: 24rpx; | |
| 503 | +} | |
| 504 | +.row { | |
| 505 | + display: flex; | |
| 506 | + align-items: center; | |
| 507 | + margin-bottom: 28rpx; | |
| 508 | + &:last-child { margin-bottom: 0; } | |
| 509 | + &.company { | |
| 510 | + font-size: 36rpx; | |
| 511 | + font-weight: 600; | |
| 512 | + color: rgba(0, 0, 0, 0.9); | |
| 513 | + padding-top: 8rpx; | |
| 514 | + line-height: 50rpx; | |
| 515 | + } | |
| 516 | + .label { | |
| 517 | + min-width: 160rpx; | |
| 518 | + max-width: 420rpx; | |
| 519 | + margin-right: 20rpx; | |
| 520 | + line-height: 44rpx; | |
| 521 | + font-size: 28rpx; | |
| 522 | + color: rgba(0, 0, 0, 0.6); | |
| 523 | + flex-shrink: 0; | |
| 524 | + } | |
| 525 | + .value { | |
| 526 | + flex: 1; | |
| 527 | + line-height: 44rpx; | |
| 528 | + font-size: 28rpx; | |
| 529 | + color: rgba(0, 0, 0, 0.9); | |
| 530 | + text-align: right; | |
| 531 | + word-break: break-all; | |
| 532 | + } | |
| 533 | + .input { | |
| 534 | + flex: 1; | |
| 535 | + height: 72rpx; | |
| 536 | + line-height: 72rpx; | |
| 537 | + padding: 0 24rpx; | |
| 538 | + border: 1rpx solid #E7E7E7; | |
| 539 | + border-radius: 8rpx; | |
| 540 | + font-size: 28rpx; | |
| 541 | + color: rgba(0,0,0,0.9); | |
| 542 | + background: #fff; | |
| 543 | + box-sizing: border-box; | |
| 544 | + text-align: right; | |
| 545 | + } | |
| 546 | + :deep(.uni-datetime-picker) { | |
| 547 | + flex: 1; | |
| 548 | + justify-content: flex-end; | |
| 549 | + :deep(.uni-datetime-picker__input) { | |
| 550 | + text-align: right; | |
| 551 | + justify-content: flex-end; | |
| 552 | + } | |
| 553 | + } | |
| 554 | +} | |
| 555 | +.attach-box { | |
| 556 | + display: flex; | |
| 557 | + flex-direction: column; | |
| 558 | + gap: 20rpx; | |
| 559 | +} | |
| 560 | +.attach-row { | |
| 561 | + display: flex; | |
| 562 | + align-items: center; | |
| 563 | + justify-content: space-between; | |
| 564 | + .attach-del { | |
| 565 | + color: #D54941; | |
| 566 | + font-size: 28rpx; | |
| 567 | + margin-left: 20rpx; | |
| 568 | + flex-shrink: 0; | |
| 569 | + } | |
| 570 | + .file-upload { | |
| 571 | + flex: 1; | |
| 572 | + } | |
| 573 | +} | |
| 574 | +.remark-text { | |
| 575 | + font-size: 28rpx; | |
| 576 | + color: rgba(0, 0, 0, 0.9); | |
| 577 | + line-height: 1.6; | |
| 578 | + white-space: pre-wrap; | |
| 579 | + width: 100%; | |
| 580 | + min-height: 200rpx; | |
| 581 | + padding: 24rpx; | |
| 582 | + border: 1rpx solid #E7E7E7; | |
| 583 | + border-radius: 8rpx; | |
| 584 | + box-sizing: border-box; | |
| 585 | + background: #fff; | |
| 586 | +} | |
| 587 | +.empty-tip { | |
| 588 | + text-align: center; | |
| 589 | + font-size: 28rpx; | |
| 590 | + color: rgba(0, 0, 0, 0.4); | |
| 591 | + padding: 24rpx 0; | |
| 592 | +} | |
| 593 | +.footer { | |
| 594 | + position: fixed; | |
| 595 | + left: 0; | |
| 596 | + right: 0; | |
| 597 | + bottom: 0; | |
| 598 | + padding: 16rpx 32rpx calc(16rpx + env(safe-area-inset-bottom)); | |
| 599 | + background: #fff; | |
| 600 | + border-top: 1rpx solid #E7E7E7; | |
| 601 | + display: flex; | |
| 602 | + gap: 24rpx; | |
| 603 | + z-index: 10; | |
| 604 | + .btn { | |
| 605 | + flex: 1; | |
| 606 | + height: 88rpx; | |
| 607 | + line-height: 88rpx; | |
| 608 | + border-radius: 8rpx; | |
| 609 | + font-size: 32rpx; | |
| 610 | + font-weight: 600; | |
| 611 | + &.cancel { | |
| 612 | + background: #F5F5F5; | |
| 613 | + color: rgba(0, 0, 0, 0.9); | |
| 614 | + border: none; | |
| 615 | + } | |
| 616 | + &.submit { | |
| 617 | + background: $theme-primary; | |
| 618 | + color: #fff; | |
| 619 | + border: none; | |
| 620 | + &[disabled] { | |
| 621 | + opacity: 0.6; | |
| 622 | + } | |
| 623 | + } | |
| 624 | + } | |
| 625 | +} | |
| 626 | +</style> | ... | ... |
pages/domestic-agreement/productRel.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <view class="product-rel"> | |
| 3 | + <view class="header"> | |
| 4 | + <image class="opCollapse" src="/static/images/title.png" /> | |
| 5 | + <text class="title">明细信息</text> | |
| 6 | + <view class="ops"> | |
| 7 | + <view class="op1" @click="toggleViewCollapse"> | |
| 8 | + <image class="opAdd" :src="collapsedView ? '/static/images/down.png' : '/static/images/up.png'" /> | |
| 9 | + <text class="op">{{ collapsedView ? '展开' : '收起' }}</text> | |
| 10 | + </view> | |
| 11 | + </view> | |
| 12 | + </view> | |
| 13 | + | |
| 14 | + <view v-if="!collapsedView" class="view-list"> | |
| 15 | + <view v-if="!items.length" class="empty-tip">暂无明细</view> | |
| 16 | + <view | |
| 17 | + v-for="(item, idx) in items" | |
| 18 | + :key="'v-' + (item.id || item.itemId || item._key || idx)" | |
| 19 | + class="card" | |
| 20 | + > | |
| 21 | + <view class="card-index">第 {{ idx + 1 }} 行</view> | |
| 22 | + <view class="row"><text class="label">名称</text><text class="value">{{ safeText(item.invoiceProductName) }}</text></view> | |
| 23 | + <view class="row"><text class="label">规格型号</text><text class="value">{{ safeText(item.productName) }}</text></view> | |
| 24 | + <view class="row"><text class="label">数量</text><text class="value">{{ formatNumber(item.quantity) }}</text></view> | |
| 25 | + <view class="row"><text class="label">单价</text><text class="value">{{ formatNumber(item.unitPrice) }}</text></view> | |
| 26 | + <view class="row"><text class="label">不含税金额</text><text class="value highlight">{{ formatNumber(item.excludingTaxAmount) }}</text></view> | |
| 27 | + <view class="row"><text class="label">税额</text><text class="value highlight">{{ formatNumber(item.taxAmount) }}</text></view> | |
| 28 | + <view class="row"><text class="label">合计金额</text><text class="value total">{{ formatNumber(item.totalAmount) }}</text></view> | |
| 29 | + <view class="row"><text class="label">交货时间</text><text class="value">{{ formatDateOnly(item.deliveryTime) }}</text></view> | |
| 30 | + </view> | |
| 31 | + | |
| 32 | + <view v-if="items.length" class="summary-card"> | |
| 33 | + <view class="summary-title">合计</view> | |
| 34 | + <view class="row"><text class="label">数量</text><text class="value">{{ formatNumber(totalQuantity) }}</text></view> | |
| 35 | + <view class="row"><text class="label">不含税金额</text><text class="value highlight">{{ formatNumber(totalExcludeTaxAmount) }}</text></view> | |
| 36 | + <view class="row"><text class="label">税额</text><text class="value highlight">{{ formatNumber(totalTaxAmount) }}</text></view> | |
| 37 | + <view class="row"><text class="label">合计金额</text><text class="value total">{{ formatNumber(totalAmount) }}</text></view> | |
| 38 | + </view> | |
| 39 | + </view> | |
| 40 | + </view> | |
| 41 | +</template> | |
| 42 | + | |
| 43 | +<script> | |
| 44 | +export default { | |
| 45 | + name: 'DomesticAgreementProductRel', | |
| 46 | + props: { | |
| 47 | + mode: { type: String, default: 'view' }, | |
| 48 | + list: { type: Array, default: function () { return [] } } | |
| 49 | + }, | |
| 50 | + data() { | |
| 51 | + return { | |
| 52 | + items: [], | |
| 53 | + collapsedView: false | |
| 54 | + } | |
| 55 | + }, | |
| 56 | + computed: { | |
| 57 | + totalQuantity() { | |
| 58 | + return round2(sum(this.items, 'quantity')) | |
| 59 | + }, | |
| 60 | + totalExcludeTaxAmount() { | |
| 61 | + return sum(this.items, 'excludingTaxAmount') | |
| 62 | + }, | |
| 63 | + totalTaxAmount() { | |
| 64 | + return sum(this.items, 'taxAmount') | |
| 65 | + }, | |
| 66 | + totalAmount() { | |
| 67 | + return sum(this.items, 'totalAmount') | |
| 68 | + } | |
| 69 | + }, | |
| 70 | + watch: { | |
| 71 | + list: { | |
| 72 | + handler(v) { | |
| 73 | + this.initItems(v) | |
| 74 | + }, | |
| 75 | + immediate: true, | |
| 76 | + deep: true | |
| 77 | + } | |
| 78 | + }, | |
| 79 | + methods: { | |
| 80 | + initItems(src) { | |
| 81 | + const arr = Array.isArray(src) ? src : [] | |
| 82 | + this.items = arr.map(x => Object.assign({}, x)) | |
| 83 | + }, | |
| 84 | + toggleViewCollapse() { | |
| 85 | + this.collapsedView = !this.collapsedView | |
| 86 | + }, | |
| 87 | + safeText(v) { | |
| 88 | + if (v === null || v === undefined || v === '') return '-' | |
| 89 | + return String(v) | |
| 90 | + }, | |
| 91 | + formatNumber(v) { | |
| 92 | + if (v === null || v === undefined || v === '') return '-' | |
| 93 | + const n = Number(v) | |
| 94 | + if (isNaN(n)) return String(v) | |
| 95 | + return n.toLocaleString('zh-CN', { maximumFractionDigits: 4 }) | |
| 96 | + }, | |
| 97 | + formatDateOnly(v) { | |
| 98 | + const s = v == null ? '' : String(v).trim() | |
| 99 | + if (!s) return '-' | |
| 100 | + if (s.length >= 10) return s.slice(0, 10) | |
| 101 | + return s | |
| 102 | + } | |
| 103 | + } | |
| 104 | +} | |
| 105 | + | |
| 106 | +function num(v) { | |
| 107 | + if (v === null || v === undefined || v === '') return 0 | |
| 108 | + const n = Number(v) | |
| 109 | + return isNaN(n) ? 0 : n | |
| 110 | +} | |
| 111 | +function round2(v) { | |
| 112 | + const n = Number(v) | |
| 113 | + if (isNaN(n)) return '' | |
| 114 | + return Math.round(n * 100) / 100 | |
| 115 | +} | |
| 116 | +function sum(list, field) { | |
| 117 | + let s = 0 | |
| 118 | + if (!Array.isArray(list)) return s | |
| 119 | + list.forEach(it => { s += num(it && it[field]) }) | |
| 120 | + return s | |
| 121 | +} | |
| 122 | +</script> | |
| 123 | + | |
| 124 | +<style lang="scss" scoped> | |
| 125 | +.product-rel { | |
| 126 | + width: 100%; | |
| 127 | + margin-top: 24rpx; | |
| 128 | +} | |
| 129 | +.header { | |
| 130 | + display: flex; | |
| 131 | + align-items: center; | |
| 132 | + padding: 16rpx 0 16rpx 32rpx; | |
| 133 | + .opCollapse { width: 6rpx; height: 32rpx; margin-right: 14rpx; } | |
| 134 | + .title { font-size: 30rpx; font-weight: 600; color: rgba(0,0,0,0.9); flex: 1; line-height: 42rpx; } | |
| 135 | + .ops { display: flex; align-items: center; padding-right: 32rpx; } | |
| 136 | + .op1 { | |
| 137 | + display: flex; | |
| 138 | + align-items: center; | |
| 139 | + padding: 0 12rpx; | |
| 140 | + height: 56rpx; | |
| 141 | + .opAdd { width: 24rpx; height: 24rpx; margin-right: 8rpx; } | |
| 142 | + .op { font-size: 26rpx; color: rgba(0,0,0,0.6); } | |
| 143 | + } | |
| 144 | +} | |
| 145 | +.view-list { | |
| 146 | + padding: 0 32rpx 24rpx; | |
| 147 | + .empty-tip { | |
| 148 | + text-align: center; | |
| 149 | + padding: 80rpx 0; | |
| 150 | + color: rgba(0,0,0,0.4); | |
| 151 | + font-size: 28rpx; | |
| 152 | + } | |
| 153 | + .card { | |
| 154 | + position: relative; | |
| 155 | + background: #fff; | |
| 156 | + border-radius: 12rpx; | |
| 157 | + padding: 32rpx 28rpx 20rpx; | |
| 158 | + margin-bottom: 24rpx; | |
| 159 | + box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04); | |
| 160 | + .card-index { | |
| 161 | + position: absolute; | |
| 162 | + top: 0; | |
| 163 | + right: 0; | |
| 164 | + background: rgba(24, 144, 255, 0.08); | |
| 165 | + color: $theme-primary; | |
| 166 | + font-size: 22rpx; | |
| 167 | + line-height: 36rpx; | |
| 168 | + padding: 0 16rpx; | |
| 169 | + border-bottom-left-radius: 12rpx; | |
| 170 | + border-top-right-radius: 12rpx; | |
| 171 | + } | |
| 172 | + .row { | |
| 173 | + display: flex; | |
| 174 | + align-items: center; | |
| 175 | + justify-content: space-between; | |
| 176 | + padding: 14rpx 0; | |
| 177 | + border-bottom: 1rpx dashed #F2F2F2; | |
| 178 | + &:last-child { border-bottom: none; } | |
| 179 | + .label { | |
| 180 | + flex-shrink: 0; | |
| 181 | + width: 220rpx; | |
| 182 | + font-size: 28rpx; | |
| 183 | + color: rgba(0,0,0,0.6); | |
| 184 | + line-height: 40rpx; | |
| 185 | + } | |
| 186 | + .value { | |
| 187 | + flex: 1; | |
| 188 | + text-align: right; | |
| 189 | + font-size: 28rpx; | |
| 190 | + color: rgba(0,0,0,0.9); | |
| 191 | + line-height: 40rpx; | |
| 192 | + overflow: hidden; | |
| 193 | + text-overflow: ellipsis; | |
| 194 | + white-space: nowrap; | |
| 195 | + &.highlight { color: #E6A23C; } | |
| 196 | + &.total { color: #D54941; font-weight: 600; font-size: 30rpx; } | |
| 197 | + } | |
| 198 | + } | |
| 199 | + } | |
| 200 | + .summary-card { | |
| 201 | + background: linear-gradient(135deg, rgba(24, 144, 255, 0.06), rgba(24, 144, 255, 0.02)); | |
| 202 | + border: 1rpx solid rgba(24, 144, 255, 0.16); | |
| 203 | + border-radius: 12rpx; | |
| 204 | + padding: 28rpx; | |
| 205 | + .summary-title { | |
| 206 | + font-size: 30rpx; | |
| 207 | + font-weight: 700; | |
| 208 | + color: $theme-primary; | |
| 209 | + margin-bottom: 12rpx; | |
| 210 | + line-height: 42rpx; | |
| 211 | + } | |
| 212 | + .row { | |
| 213 | + display: flex; | |
| 214 | + align-items: center; | |
| 215 | + justify-content: space-between; | |
| 216 | + padding: 12rpx 0; | |
| 217 | + border-bottom: 1rpx dashed rgba(24, 144, 255, 0.12); | |
| 218 | + &:last-child { border-bottom: none; } | |
| 219 | + .label { | |
| 220 | + flex-shrink: 0; | |
| 221 | + width: 220rpx; | |
| 222 | + font-size: 28rpx; | |
| 223 | + color: rgba(0,0,0,0.6); | |
| 224 | + line-height: 40rpx; | |
| 225 | + } | |
| 226 | + .value { | |
| 227 | + flex: 1; | |
| 228 | + text-align: right; | |
| 229 | + font-size: 28rpx; | |
| 230 | + color: rgba(0,0,0,0.9); | |
| 231 | + line-height: 40rpx; | |
| 232 | + font-weight: 500; | |
| 233 | + &.highlight { color: #E6A23C; } | |
| 234 | + &.total { color: #D54941; font-weight: 700; font-size: 32rpx; } | |
| 235 | + } | |
| 236 | + } | |
| 237 | + } | |
| 238 | +} | |
| 239 | +</style> | ... | ... |
| ... | ... | @@ -181,11 +181,15 @@ export default { |
| 181 | 181 | Name = _contractType |
| 182 | 182 | }else if(_contractType === 'PROCESS_STD_AGMT'){ |
| 183 | 183 | Name = 'AGMT_VIEW' |
| 184 | + }else if(_contractType === 'PROCUREMENT_CONTRACT'){ | |
| 185 | + Name = 'PROCUREMENT_CONTRACT' | |
| 184 | 186 | }else{ |
| 185 | 187 | Name = this.auditCtx.bizFlag || '' |
| 186 | 188 | } |
| 187 | 189 | }else if (_contractType === 'PROCESS_STD_AGMT') { |
| 188 | 190 | Name = 'PROCESS_STD_AGMT' |
| 191 | + }else if (_contractType === 'PROCUREMENT_CONTRACT') { | |
| 192 | + Name = 'PROCUREMENT_CONTRACT' | |
| 189 | 193 | }else{ |
| 190 | 194 | Name = this.auditCtx.bizFlag || '' |
| 191 | 195 | } | ... | ... |
| ... | ... | @@ -44,6 +44,8 @@ export default { |
| 44 | 44 | let Name = '' |
| 45 | 45 | if (_contractType === 'PROCESS_STD_AGMT') { |
| 46 | 46 | Name = 'PROCESS_STD_AGMT' |
| 47 | + }else if (_contractType === 'PROCUREMENT_CONTRACT') { | |
| 48 | + Name = 'PROCUREMENT_CONTRACT' | |
| 47 | 49 | }else{ |
| 48 | 50 | Name = this.auditCtx.bizFlag || '' |
| 49 | 51 | } | ... | ... |
| ... | ... | @@ -197,6 +197,12 @@ export default { |
| 197 | 197 | icon: '/static/images/index/revoke_list.png', |
| 198 | 198 | link: '/pages/supple-plan/index', |
| 199 | 199 | name: 'SupplePlan' |
| 200 | + }, | |
| 201 | + { | |
| 202 | + text: '内贸合同管理', | |
| 203 | + icon: '/static/images/index/draft_order.png', | |
| 204 | + link: '/pages/domestic-agreement/index', | |
| 205 | + name: 'DomesticAgreement' | |
| 200 | 206 | } |
| 201 | 207 | ] |
| 202 | 208 | }, | ... | ... |
| ... | ... | @@ -28,6 +28,7 @@ import ConfirmationFormApprove from '@/pages/confirmation_form/approve.vue' |
| 28 | 28 | import FollowUpFormViewer from '@/pages/follow_up_form/viewer.vue' |
| 29 | 29 | import DomesticPlanViewer from '@/pages/domestic-plan/domesticPlanViewer.vue' |
| 30 | 30 | import SupplePlanViewer from '@/pages/supple-plan/supplePlanViewer.vue' |
| 31 | +import DomesticAgreementViewer from '@/pages/domestic-agreement/domesticAgreementViewer.vue' | |
| 31 | 32 | |
| 32 | 33 | export default function registerComponents(Vue) { |
| 33 | 34 | Vue.component('CustomerDevelopViewer', CustomerDevelopViewer) |
| ... | ... | @@ -60,4 +61,5 @@ export default function registerComponents(Vue) { |
| 60 | 61 | Vue.component('AgmtViewer', AgmtViewer) |
| 61 | 62 | Vue.component('DomesticPlanViewer', DomesticPlanViewer) |
| 62 | 63 | Vue.component('SupplePlanViewer', SupplePlanViewer) |
| 64 | + Vue.component('DomesticAgreementViewer', DomesticAgreementViewer) | |
| 63 | 65 | } | ... | ... |
| ... | ... | @@ -147,6 +147,11 @@ export const getSysFlowComponentPath = (bizFlag) => { |
| 147 | 147 | break; |
| 148 | 148 | case 'PLAN_REPLENISH_EDIT': // 补库计划 |
| 149 | 149 | componentPath = 'SupplePlanViewer'; // 补库计划-审批 |
| 150 | + case 'PROCUREMENT_CONTRACT': // 内贸协议 | |
| 151 | + componentPath = 'DomesticAgreementViewer'; // 内贸协议-审批详情 | |
| 152 | + break; | |
| 153 | + case 'PROCUREMENT_CONTRACT_EDIT': // 内贸协议 | |
| 154 | + componentPath = 'DomesticAgreementViewer'; // 内贸协议-审批 | |
| 150 | 155 | break; |
| 151 | 156 | } |
| 152 | 157 | return componentPath; | ... | ... |