Commit bb75c34b88592ea22e3b8bdb42f43d242bd4585e

Authored by 史婷婷
2 parents 33745373 2d7f90b5

Merge remote-tracking branch 'origin/cjerp-1.0_shipping' into test_cjerp

Showing 48 changed files with 3684 additions and 519 deletions

Too many changes to show.

To preserve performance only 48 of 103 files are displayed.

1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2 <project version="4">
3 3 <component name="ChangeListManager">
4   - <list default="true" id="22e3db16-f3f9-44cc-b7ca-0b5f75df2820" name="Changes" comment="" />
  4 + <list default="true" id="22e3db16-f3f9-44cc-b7ca-0b5f75df2820" name="Changes" comment="">
  5 + <change beforePath="$PROJECT_DIR$/pages/draft_order/modify.vue" beforeDir="false" afterPath="$PROJECT_DIR$/pages/draft_order/modify.vue" afterDir="false" />
  6 + </list>
5 7 <option name="SHOW_DIALOG" value="false" />
6 8 <option name="HIGHLIGHT_CONFLICTS" value="true" />
7 9 <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
... ... @@ -48,6 +50,11 @@
48 50 <ui_properties converted="true" />
49 51 </component>
50 52 <component name="Git.Settings">
  53 + <option name="RECENT_BRANCH_BY_REPOSITORY">
  54 + <map>
  55 + <entry key="$PROJECT_DIR$" value="publish_cjerp" />
  56 + </map>
  57 + </option>
51 58 <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
52 59 </component>
53 60 <component name="ProjectColorInfo">{
... ... @@ -164,7 +171,19 @@
164 171 <map>
165 172 <entry key="MAIN">
166 173 <value>
167   - <State />
  174 + <State>
  175 + <option name="FILTERS">
  176 + <map>
  177 + <entry key="branch">
  178 + <value>
  179 + <list>
  180 + <option value="cjerp-1.0_20251220" />
  181 + </list>
  182 + </value>
  183 + </entry>
  184 + </map>
  185 + </option>
  186 + </State>
168 187 </value>
169 188 </entry>
170 189 </map>
... ...
  1 +import request from '@/utils/request'
  2 +import { ContentTypeEnum } from '@/utils/httpEnum';
  3 +
  4 +const baseUrl = '/requestCarTicket';
  5 +// 查询列表
  6 +export function queryApi(params) {
  7 + return request({
  8 + url: baseUrl + `/query`,
  9 + method: 'get',
  10 + params
  11 + })
  12 +}
  13 +
  14 +// 根据ID查询详情数据
  15 +export function getDetailApi(id) {
  16 + return request({
  17 + url: baseUrl,
  18 + method: 'get',
  19 + params: { id }
  20 + })
  21 +}
  22 +
  23 +// 新增保存
  24 +export function createApi(params) {
  25 + return request({
  26 + url: baseUrl,
  27 + method: 'post',
  28 + data: params,
  29 + contentType: ContentTypeEnum.JSON
  30 + })
  31 +}
  32 +
  33 +
  34 +// 修改保存
  35 +export function updateApi(params) {
  36 + return request({
  37 + url: baseUrl,
  38 + method: 'put',
  39 + data: params,
  40 + contentType: ContentTypeEnum.JSON
  41 + })
  42 +}
  43 +
... ...
  1 +import request from '@/utils/request'
  2 +import { ContentTypeEnum } from '@/utils/httpEnum';
  3 +
  4 +const baseUrl = '/delayedShipment';
  5 +// 查询列表
  6 +export function queryApi(params) {
  7 + return request({
  8 + url: baseUrl + `/query`,
  9 + method: 'get',
  10 + params
  11 + })
  12 +}
  13 +
  14 +// 根据ID查询详情数据
  15 +export function getDetailApi(id) {
  16 + return request({
  17 + url: baseUrl,
  18 + method: 'get',
  19 + params: { id }
  20 + })
  21 +}
  22 +
  23 +// 取消
  24 +export function cancelApi(id) {
  25 + return request({
  26 + url: baseUrl + '/cancel',
  27 + method: 'get',
  28 + params: { id }
  29 + })
  30 +}
  31 +
  32 +// 延期发货按钮-选择的数据查询
  33 +export function getShipmentPlanDetailApi(id) {
  34 + return request({
  35 + url: '/shipments/plan/detail',
  36 + method: 'get',
  37 + params: { id }
  38 + })
  39 +}
  40 +
  41 +// 新增保存
  42 +export function createApi(params) {
  43 + return request({
  44 + url: baseUrl,
  45 + method: 'post',
  46 + data: params,
  47 + contentType: ContentTypeEnum.JSON
  48 + })
  49 +}
  50 +
  51 +
  52 +// 修改保存
  53 +export function updateApi(params) {
  54 + return request({
  55 + url: baseUrl,
  56 + method: 'put',
  57 + data: params,
  58 + contentType: ContentTypeEnum.JSON
  59 + })
  60 +}
  61 +
... ...
... ... @@ -2,13 +2,54 @@ import request from '@/utils/request'
2 2 import { ContentTypeEnum } from '@/utils/httpEnum';
3 3
4 4 const baseUrl = '/draftRequestCarTicket';
  5 +// 查询列表
  6 +export function queryApi(params) {
  7 + return request({
  8 + url: baseUrl + `/query`,
  9 + method: 'get',
  10 + params
  11 + })
  12 +}
  13 +
  14 +// 根据ID查询详情数据
  15 +export function getDetailApi(id) {
  16 + return request({
  17 + url: baseUrl,
  18 + method: 'get',
  19 + params: { id }
  20 + })
  21 +}
  22 +
  23 +
  24 +// 取消
  25 +export function cancelApi(id) {
  26 + return request({
  27 + url: baseUrl + '/cancel',
  28 + method: 'get',
  29 + params: { id }
  30 + })
  31 +}
5 32
6 33 // 新增保存
7 34 export function createApi(params) {
8 35 return request({
9   - url: `${baseUrl}`,
  36 + url: baseUrl,
10 37 method: 'post',
11 38 data: params,
12 39 contentType: ContentTypeEnum.JSON
13 40 })
14 41 }
  42 +
  43 +
  44 +
  45 +// 修改保存
  46 +export function updateApi(params) {
  47 + return request({
  48 + url: baseUrl,
  49 + method: 'put',
  50 + data: params,
  51 + contentType: ContentTypeEnum.JSON
  52 + })
  53 +}
  54 +
  55 +
... ...
  1 +import request from '@/utils/request'
  2 +import { ContentTypeEnum } from '@/utils/httpEnum';
  3 +
  4 +const baseUrl = '/shipments/order';
  5 +// 查询列表
  6 +export function queryApi(params) {
  7 + return request({
  8 + url: baseUrl + `/query`,
  9 + method: 'get',
  10 + params
  11 + })
  12 +}
  13 +
  14 +// 根据ID查询详情数据
  15 +export function getDetailApi(id) {
  16 + return request({
  17 + url: baseUrl,
  18 + method: 'get',
  19 + params: { id }
  20 + })
  21 +}
  22 +
  23 +// 新增保存
  24 +export function createApi(params) {
  25 + return request({
  26 + url: baseUrl,
  27 + method: 'post',
  28 + data: params,
  29 + contentType: ContentTypeEnum.FORM_URLENCODED
  30 + })
  31 +}
  32 +
  33 +
  34 +// 修改保存
  35 +export function updateApi(params) {
  36 + return request({
  37 + url: baseUrl,
  38 + method: 'put',
  39 + data: params,
  40 + contentType: ContentTypeEnum.FORM_URLENCODED
  41 + })
  42 +}
  43 +
  44 +
  45 +// 检查发货计划是否可以填写实发数
  46 +// [id1, id2, ...]
  47 +export function checkApi(ids) {
  48 + return request({
  49 + url: baseUrl + '/check',
  50 + method: 'post',
  51 + data: ids,
  52 + contentType: ContentTypeEnum.JSON
  53 + })
  54 +}
  55 +
  56 +// 根据发货计划ID查询发货订单列表
  57 +export function listByShipmentOrderId(shipmentsOrderId) {
  58 + return request({
  59 + url: baseUrl + '/listByShipmentOrderId',
  60 + method: 'get',
  61 + params: { shipmentsOrderId }
  62 + })
  63 +}
  64 +
  65 +// 根据发货计划ID查询发货订单列表
  66 +// {
  67 +// id,
  68 +// detailList,
  69 +// type,
  70 +// }
  71 +export function dataReplenishInput(params) {
  72 + return request({
  73 + url: baseUrl + '/dataReplenishInput',
  74 + method: 'post',
  75 + data: params,
  76 + contentType: ContentTypeEnum.JSON
  77 + })
  78 +}
  79 +
  80 +// 保存签收单
  81 +// {
  82 +// fileId: String;
  83 +// fileName: String;
  84 +// shipmentsOrderId: String;
  85 +// }
  86 +export function saveSignInTicket(params) {
  87 + return request({
  88 + url: baseUrl + '/saveSignInTicket',
  89 + method: 'get',
  90 + params: params,
  91 + })
  92 +}
  93 +
  94 +// 查询发货计划详情
  95 +export function queryDetail(params) {
  96 + return request({
  97 + url: '/shipments/plan/detail/query',
  98 + method: 'get',
  99 + params: params,
  100 + })
  101 +}
  102 +
  103 +// 发货单-拆分
  104 +export function splitDataApi(params) {
  105 + return request({
  106 + url: '/shipments/plan/detail/split',
  107 + method: 'post',
  108 + data: params,
  109 + contentType: ContentTypeEnum.JSON
  110 + })
  111 +}
\ No newline at end of file
... ...
  1 +import request from '@/utils/request'
  2 +import { ContentTypeEnum } from '@/utils/httpEnum';
  3 +
  4 +const baseUrl = '/shipments/replenishmentOrder';
  5 +// 查询列表
  6 +export function queryApi(params) {
  7 + return request({
  8 + url: baseUrl + `/query`,
  9 + method: 'get',
  10 + params
  11 + })
  12 +}
  13 +
  14 +// 根据ID查询详情数据
  15 +export function getDetailApi(id) {
  16 + return request({
  17 + url: baseUrl,
  18 + method: 'get',
  19 + params: { id }
  20 + })
  21 +}
  22 +
  23 +// 获取订单编号
  24 +export function getCodeApi(purchaseOrderId) {
  25 + return request({
  26 + url: baseUrl + '/getCode',
  27 + method: 'get',
  28 + params: { purchaseOrderId }
  29 + })
  30 +}
  31 +
  32 +
  33 +// 取消
  34 +export function cancelApi(id) {
  35 + return request({
  36 + url: baseUrl + '/cancel',
  37 + method: 'get',
  38 + params: { id }
  39 + })
  40 +}
  41 +
  42 +// 新增保存
  43 +export function createApi(params) {
  44 + return request({
  45 + url: baseUrl,
  46 + method: 'post',
  47 + data: params,
  48 + contentType: ContentTypeEnum.JSON
  49 + })
  50 +}
  51 +
  52 +
  53 +// 填写计划补货时间
  54 +export function fillRestockTimeApi(params) {
  55 + return request({
  56 + url: baseUrl + '/fillRestockTime',
  57 + method: 'post',
  58 + data: params,
  59 + contentType: ContentTypeEnum.JSON
  60 + })
  61 +}
  62 +
  63 +
  64 +// 修改保存
  65 +export function updateApi(params) {
  66 + return request({
  67 + url: baseUrl,
  68 + method: 'put',
  69 + data: params,
  70 + contentType: ContentTypeEnum.JSON
  71 + })
  72 +}
  73 +
  74 +// 通过订单ID 补货单-获取订货单列表
  75 +export function loadOrderApi(ids) {
  76 + return request({
  77 + url: `/selector/replenishment/order/load`,
  78 + method: 'post',
  79 + data: ids,
  80 + contentType: ContentTypeEnum.JSON
  81 + })
  82 +}
... ...
... ... @@ -4,9 +4,6 @@
4 4 class="scroll"
5 5 scroll-y
6 6 :lower-threshold="lowerThreshold"
7   - :refresher-enabled="enableRefresh"
8   - :refresher-triggered="refresherTriggered"
9   - @refresherrefresh="onRefresh"
10 7 @scrolltolower="onLoadMore"
11 8 @scroll="onScroll"
12 9 >
... ...
1 1 <template>
2   - <view class="button-bar">
  2 + <view v-if="effectiveButtons.length" class="button-bar">
3 3 <view v-if="showMoreButton" class="more-link" @click="toggleMore">更多</view>
4 4 <view class="button-grid" :style="{ gridTemplateColumns: gridColumns }">
5 5 <view v-for="(btn, idx) in visibleButtons" :key="idx" class="action-button" :class="buttonClass(btn)" :style="buttonStyle(btn)" @click="emitClick(btn)">{{ btn.text }}</view>
... ...
... ... @@ -3,7 +3,7 @@
3 3 <view class="filter-modal">
4 4 <view class="header">
5 5 <text class="title">{{ title }}</text>
6   - <text class="close" @click="onClose">×</text>
  6 + <text class="close" @click="onClose"></text>
7 7 </view>
8 8
9 9 <view class="body">
... ... @@ -110,8 +110,12 @@ export default {
110 110 text-align: center;
111 111 }
112 112 .close {
113   - font-size: 36rpx;
114   - color: #666;
  113 + width: 48rpx;
  114 + height: 48rpx;
  115 + background-image: url('~@/static/images/flow/close_icon.png');
  116 + background-repeat: no-repeat;
  117 + background-position: right center;
  118 + background-size: cover;
115 119 }
116 120 .body {
117 121 flex: 1 1 auto;
... ...
... ... @@ -233,13 +233,13 @@ export default {
233 233 .cancel { color: rgba(0,0,0,0.6); font-size: 28rpx; }
234 234 .ok { color: $theme-primary; font-size: 28rpx; }
235 235 .sheet-search { padding: 16rpx 24rpx; }
236   -.sheet-body {
237   - flex: 1 1 auto; overflow-y: auto; padding: 24rpx;
  236 +.sheet-body {
  237 + flex: 1 1 auto; overflow-y: auto; padding: 24rpx;
238 238 background: #f3f3f3;
239 239 }
240 240 .card { background: #fff; }
241   -.card.selected {
242   - background-color: #fff;
  241 +.card.selected {
  242 + background-color: #fff;
243 243 position: relative;
244 244 &::after {
245 245 content: '';
... ...
... ... @@ -650,9 +650,129 @@
650 650 }
651 651 },
652 652 {
653   - "path": "pages/message/detail",
  653 + "path": "pages/invoice/index",
654 654 "style": {
655   - "navigationBarTitleText": "消息详情",
  655 + "navigationBarTitleText": "发货单",
  656 + "navigationBarBackgroundColor": "#ffffff",
  657 + "navigationBarTextStyle": "black"
  658 + }
  659 + },
  660 + {
  661 + "path": "pages/invoice/detail",
  662 + "style": {
  663 + "navigationBarTitleText": "发货单详情",
  664 + "navigationBarBackgroundColor": "#ffffff",
  665 + "navigationBarTextStyle": "black"
  666 + }
  667 + },
  668 + {
  669 + "path": "pages/invoice/fill",
  670 + "style": {
  671 + "navigationBarTitleText": "发货单填写实发数",
  672 + "navigationBarBackgroundColor": "#ffffff",
  673 + "navigationBarTextStyle": "black"
  674 + }
  675 + },
  676 + {
  677 + "path": "pages/delay_invoice/index",
  678 + "style": {
  679 + "navigationBarTitleText": "延期发货单",
  680 + "navigationBarBackgroundColor": "#ffffff",
  681 + "navigationBarTextStyle": "black"
  682 + }
  683 + },
  684 + {
  685 + "path": "pages/delay_invoice/detail",
  686 + "style": {
  687 + "navigationBarTitleText": "延期发货单详情",
  688 + "navigationBarBackgroundColor": "#ffffff",
  689 + "navigationBarTextStyle": "black"
  690 + }
  691 + },
  692 + {
  693 + "path": "pages/delay_invoice/modify",
  694 + "style": {
  695 + "navigationBarTitleText": "编辑延期发货单",
  696 + "navigationBarBackgroundColor": "#ffffff",
  697 + "navigationBarTextStyle": "black"
  698 + }
  699 + },
  700 + {
  701 + "path": "pages/draft_order/index",
  702 + "style": {
  703 + "navigationBarTitleText": "草稿要车单",
  704 + "navigationBarBackgroundColor": "#ffffff",
  705 + "navigationBarTextStyle": "black"
  706 + }
  707 + },
  708 + {
  709 + "path": "pages/draft_order/detail",
  710 + "style": {
  711 + "navigationBarTitleText": "草稿要车单详情",
  712 + "navigationBarBackgroundColor": "#ffffff",
  713 + "navigationBarTextStyle": "black"
  714 + }
  715 + },
  716 + {
  717 + "path": "pages/draft_order/modify",
  718 + "style": {
  719 + "navigationBarTitleText": "编辑草稿要车单",
  720 + "navigationBarBackgroundColor": "#ffffff",
  721 + "navigationBarTextStyle": "black"
  722 + }
  723 + },
  724 + {
  725 + "path": "pages/car_request_order/index",
  726 + "style": {
  727 + "navigationBarTitleText": "要车单",
  728 + "navigationBarBackgroundColor": "#ffffff",
  729 + "navigationBarTextStyle": "black"
  730 + }
  731 + },
  732 + {
  733 + "path": "pages/car_request_order/detail",
  734 + "style": {
  735 + "navigationBarTitleText": "要车单详情",
  736 + "navigationBarBackgroundColor": "#ffffff",
  737 + "navigationBarTextStyle": "black"
  738 + }
  739 + },
  740 + {
  741 + "path": "pages/replenishment_order/index",
  742 + "style": {
  743 + "navigationBarTitleText": "补货单",
  744 + "navigationBarBackgroundColor": "#ffffff",
  745 + "navigationBarTextStyle": "black"
  746 + }
  747 + },
  748 + {
  749 + "path": "pages/replenishment_order/add",
  750 + "style": {
  751 + "navigationBarTitleText": "新增补货单",
  752 + "navigationBarBackgroundColor": "#ffffff",
  753 + "navigationBarTextStyle": "black"
  754 + }
  755 + },
  756 + {
  757 + "path": "pages/replenishment_order/detail",
  758 + "style": {
  759 + "navigationBarTitleText": "补货单详情",
  760 + "navigationBarBackgroundColor": "#ffffff",
  761 + "navigationBarTextStyle": "black"
  762 + }
  763 + },
  764 + {
  765 + "path": "pages/replenishment_order/modify",
  766 + "style": {
  767 + "navigationBarTitleText": "编辑补货单",
  768 + "navigationBarBackgroundColor": "#ffffff",
  769 + "navigationBarTextStyle": "black"
  770 + }
  771 + },
  772 + {
  773 + "path": "pages/replenishment_order/fill",
  774 + "style": {
  775 + "navigationBarTitleText": "填写补货时间",
656 776 "navigationBarBackgroundColor": "#ffffff",
657 777 "navigationBarTextStyle": "black"
658 778 }
... ...
  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">{{ form.orderingUnitName }}</text>
  7 + <view class="row"><text class="label">要车日期</text><text class="value">{{ form.requestCarDate }}</text></view>
  8 + <view class="row"><text class="label">要车办事处</text><text class="value">{{ form.deptName }}</text></view>
  9 + <view class="row"><text class="label">计划装货日期</text><text class="value">{{ form.deliveryDate }}</text></view>
  10 + <view class="row"><text class="label">装货厂别</text><text class="value">{{ form.workshopName }}</text></view>
  11 + <view class="row"><text class="label">订单编号</text><text class="value">{{ form.orderNo }}</text></view>
  12 + <view class="row"><text class="label">卸货地点</text><text class="value">{{ form.destination }}</text></view>
  13 + <view class="row"><text class="label">计划吨位(kg)</text><text class="value">{{ form.quantity }}</text></view>
  14 + <view class="row"><text class="label">接货人/联络人</text><text class="value">{{ form.consignee }}</text></view>
  15 + <view class="row"><text class="label">联系电话</text><text class="value">{{ form.phone }}</text></view>
  16 + <view class="row"><text class="label">装货时间</text><text class="value">{{ form.loadingTime }}</text></view>
  17 + <view class="row"><text class="label">外办审核人</text><text class="value">{{ form.externalAuditorName }}</text></view>
  18 + <view class="row"><text class="label">经营办审核人</text><text class="value">{{ form.businessOfficeAuditorName }}</text></view>
  19 + <view class="row"><text class="label">运作科审核人</text><text class="value">{{ form.operationsDepartmentAuditorName }}</text></view>
  20 + <view class="row"><text class="label">回货计划安排</text><text class="value">{{ form.returnPlanArrangement }}</text></view>
  21 + <view class="row"><text class="label">特殊需求、其他等</text><text class="value">{{ form.other }}</text></view>
  22 + <view class="row"><text class="label">装货特别要求/需求</text><text class="value">{{ form.specialLoadingRequirement }}</text></view>
  23 + </view>
  24 + </view>
  25 + </scroll-view>
  26 + </view>
  27 +</template>
  28 +
  29 +<script>
  30 +import { getDetailApi } from '@/api/car_request_order.js'
  31 +
  32 +export default {
  33 + name: 'CarRequestOrderDetail',
  34 + data() {
  35 + return {
  36 + form: {},
  37 + }
  38 + },
  39 + computed: {
  40 + },
  41 + onLoad(query) {
  42 + const id = (query && (query.id || query.code)) || ''
  43 + if (id) this.loadDetail(id)
  44 + },
  45 + methods: {
  46 + async loadDetail(id) {
  47 + try {
  48 + const res = await getDetailApi(id)
  49 + this.form = res.data || {}
  50 + } catch (e) {
  51 + this.form = {}
  52 + }
  53 + }
  54 + }
  55 +}
  56 +</script>
  57 +
  58 +<style lang="scss" scoped>
  59 +.page {
  60 + display: flex;
  61 + flex-direction: column;
  62 + height: 100vh;
  63 +}
  64 +
  65 +.scroll {
  66 + flex: 1;
  67 + background: #f3f3f3;
  68 +}
  69 +
  70 +.detail-page {
  71 +}
  72 +
  73 +.section {
  74 + padding: 32rpx;
  75 + background: #fff;
  76 + margin-bottom: 20rpx;
  77 + position: relative;
  78 +}
  79 +
  80 +.row {
  81 + display: flex;
  82 + margin-bottom: 28rpx;
  83 +
  84 + &:last-child {
  85 + margin-bottom: 0;
  86 + }
  87 +
  88 + &.company {
  89 + font-size: 36rpx;
  90 + font-weight: 600;
  91 + color: rgba(0, 0, 0, 0.9);
  92 + padding-top: 10rpx;
  93 + margin-bottom: 32rpx;
  94 + line-height: 50rpx;
  95 + }
  96 +
  97 + .label {
  98 + width: 240rpx;
  99 + line-height: 32rpx;
  100 + font-size: 28rpx;
  101 + color: rgba(0, 0, 0, 0.6);
  102 + }
  103 +
  104 + .value {
  105 + flex: 1;
  106 + line-height: 32rpx;
  107 + font-size: 28rpx;
  108 + color: rgba(0, 0, 0, 0.9);
  109 + text-align: right;
  110 + word-break: break-all;
  111 + }
  112 +}
  113 +
  114 +.title-header {
  115 + background-color: #fff;
  116 + display: flex;
  117 + align-items: center;
  118 + padding: 32rpx 32rpx 22rpx;
  119 + border-bottom: 1rpx dashed #f0f0f0;
  120 +
  121 + &_icon {
  122 + width: 32rpx;
  123 + height: 28rpx;
  124 + margin-right: 16rpx;
  125 + }
  126 +
  127 + span {
  128 + color: rgba(0, 0, 0, 0.9);
  129 + font-size: 32rpx;
  130 + line-height: 44rpx;
  131 + font-weight: 600;
  132 + }
  133 +}
  134 +</style>
... ...
  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 +
  15 + <!-- 列表卡片组件 -->
  16 + <view class="list-box">
  17 + <card-list ref="cardRef" :fetch-fn="fetchList" :query="query" :extra="extraParams" row-key="id"
  18 + :enable-refresh="true" :enable-load-more="true" @loaded="onCardLoaded" @error="onCardError">
  19 + <template v-slot="{ item, selected }">
  20 + <view class="card" @click.stop="onCardClick(item)">
  21 + <view class="card-header">
  22 + <text class="title omit2">{{ item.orderingUnitName }}</text>
  23 + </view>
  24 + <view class="info-row">
  25 + <text>订单编号</text><text>{{ item.orderNo || '-' }}</text>
  26 + </view>
  27 + <view class="info-row">
  28 + <text>要车办事处</text><text>{{ item.deptName || '-' }}</text>
  29 + </view>
  30 + <view class="info-row">
  31 + <text>装货厂别</text><text>{{ item.workshopName || '-' }}</text>
  32 + </view>
  33 + <view class="info-row">
  34 + <text>要车日期</text><text>{{ item.requestCarDate || '-' }}</text>
  35 + </view>
  36 + </view>
  37 + </template>
  38 + </card-list>
  39 + </view>
  40 +
  41 +
  42 +
  43 + <!-- 筛选弹框 -->
  44 + <filter-modal :visible.sync="filterVisible" :value.sync="filterForm" title="筛选" @reset="onFilterReset"
  45 + @confirm="onFilterConfirm">
  46 + <template v-slot="{ model }">
  47 + <view class="filter-form">
  48 + <view class="form-item">
  49 + <view class="label">办事处</view>
  50 + <uni-easyinput v-model="model.deptName" placeholder="请输入办事处" :inputBorder="false"
  51 + placeholderStyle="font-size:14px" @input="onDeptNameInput" />
  52 + </view>
  53 +
  54 + <view class="form-item">
  55 + <view class="label">装货厂别</view>
  56 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  57 + v-model="model.workshopId" @change="onWorkshopChange" :localdata="workshopOptions" />
  58 + </view>
  59 +
  60 + <view class="form-item">
  61 + <view class="label">要车日期</view>
  62 + <uni-datetime-picker type="daterange" v-model="model.dateRange" start="2023-01-01" @change="onDateChange($event, model)" />
  63 + </view>
  64 + </view>
  65 + </template>
  66 + </filter-modal>
  67 + </view>
  68 +</template>
  69 +
  70 +<script>
  71 +import CardList from '@/components/card/index.vue'
  72 +import FilterModal from '@/components/filter/index.vue'
  73 +import { workshopQueryApi } from '@/api/devManage.js'
  74 +import SingleSelectSheet from '@/components/single-select/index.vue'
  75 +import {
  76 + queryApi
  77 +} from '@/api/car_request_order.js'
  78 +import {
  79 + getDicByCodes
  80 +} from '@/utils/dic'
  81 +import {
  82 + getDicName
  83 +} from '@/utils/dic.js'
  84 +
  85 +export default {
  86 + components: {
  87 + CardList,
  88 + FilterModal,
  89 + SingleSelectSheet
  90 + },
  91 + data() {
  92 + return {
  93 + searchKeyword: '',
  94 + searchKeywordDebounced: '',
  95 + tabs: [],
  96 + // 给到 card 的筛选值
  97 + query: {
  98 + status: '',
  99 + companySuggestedCategory: '',
  100 + dateRange: []
  101 + },
  102 + extraParams: {},
  103 +
  104 + // 批量选择
  105 + rowKey: 'id',
  106 + currentItems: [],
  107 +
  108 + // 筛选弹框
  109 + filterVisible: false,
  110 + filterForm: {
  111 + status: '',
  112 + dateRange: []
  113 + },
  114 + dicOptions: {
  115 + SHIP_ORDER_STATUS: [],
  116 + },
  117 + statusLocal: [],
  118 + workshopOptions: [],
  119 + }
  120 + },
  121 + computed: {
  122 + extraCombined() {
  123 + return {
  124 + searchKey: this.searchKeywordDebounced || undefined
  125 + }
  126 + }
  127 + },
  128 + watch: {
  129 + extraCombined: {
  130 + deep: true,
  131 + handler(v) {
  132 + this.extraParams = v
  133 + },
  134 + immediate: true
  135 + },
  136 +
  137 + },
  138 + created() {
  139 + this.loadWorkshopOptions()
  140 + },
  141 + onLoad() { },
  142 + // 页面触底兜底:当页面自身滚动到底部时,转调卡片组件加载更多
  143 + onReachBottom() {
  144 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) {
  145 + this.$refs.cardRef.onLoadMore()
  146 + }
  147 + },
  148 + beforeDestroy() {
  149 + if (this.searchDebounceTimer) {
  150 + clearTimeout(this.searchDebounceTimer)
  151 + this.searchDebounceTimer = null
  152 + }
  153 + },
  154 + methods: {
  155 + async loadWorkshopOptions() {
  156 + try {
  157 + const res = await workshopQueryApi({ pageIndex: 1, pageSize: 9999 })
  158 + const list = (res && res.data && res.data.datas) || []
  159 + this.workshopOptions = list.map(it => ({ text: it.name || it.workshopName || '', value: it.id || it.workshopId || '' }))
  160 + } catch (e) {
  161 + this.workshopOptions = []
  162 + }
  163 + },
  164 + onCardLoaded({
  165 + items
  166 + }) {
  167 + this.currentItems = items
  168 + },
  169 + onCardError() {
  170 + uni.showToast({
  171 + title: '列表加载失败',
  172 + icon: 'none'
  173 + })
  174 + },
  175 + // 输入实时搜索:1200ms 防抖,仅在停止输入超过阈值后刷新
  176 + onSearchInput(val) {
  177 + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer)
  178 + this.searchDebounceTimer = setTimeout(() => {
  179 + this.searchKeywordDebounced = this.searchKeyword
  180 + this.searchDebounceTimer = null
  181 + }, 1200)
  182 + },
  183 + // uni-search-bar 确认搜索:更新关键字并触发 CardList 刷新
  184 + search(e) {
  185 + const val = e && e.value != null ? e.value : this.searchKeyword
  186 + this.searchKeyword = val
  187 + this.searchKeywordDebounced = val
  188 + },
  189 + onAdd() {
  190 + uni.navigateTo({
  191 + url: '/pages/credit_manage/add'
  192 + })
  193 + },
  194 + openFilter() {
  195 + this.filterVisible = true
  196 + },
  197 + onFilterReset(payload) {
  198 + this.filterForm = payload
  199 + },
  200 + onFilterConfirm(payload) {
  201 + if ((payload.status === '' || payload.status == null) && this.filterForm.status !== '') {
  202 + payload.status = this.filterForm.status
  203 + }
  204 + this.query = {
  205 + ...payload
  206 + }
  207 + },
  208 + onStatusChange(e) {
  209 + const raw = e && e.detail && e.detail.value !== undefined ?
  210 + e.detail.value :
  211 + (e && e.value !== undefined ? e.value : '')
  212 + this.filterForm.status = raw
  213 + },
  214 +
  215 + // 列表接口(真实请求)
  216 + fetchList({
  217 + pageIndex,
  218 + pageSize,
  219 + query,
  220 + extra
  221 + }) {
  222 + const params = {
  223 + pageIndex,
  224 + pageSize,
  225 + ...extra,
  226 + ...query
  227 + }
  228 + if (Array.isArray(params.dateRange) && params.dateRange.length === 2) {
  229 + params.requestCarDateStart = params.dateRange[0]
  230 + params.requestCarDateEnd = params.dateRange[1]
  231 + delete params.dateRange
  232 + }
  233 + if (this.searchKeywordDebounced) {
  234 + params.searchKey = this.searchKeywordDebounced
  235 + }
  236 + return queryApi(params)
  237 + .then(res => {
  238 + const _data = res.data || {};
  239 + const records = _data.datas || [];
  240 + const totalCount = _data.totalCount || 0;
  241 + const hasNext = _data.hasNext || false
  242 + return {
  243 + records,
  244 + totalCount,
  245 + hasNext
  246 + }
  247 + })
  248 + .catch(err => {
  249 + console.error('fetchList error', err)
  250 + this.onCardError()
  251 + return {
  252 + records: [],
  253 + totalCount: 0,
  254 + hasNext: false
  255 + }
  256 + })
  257 + },
  258 + onCardClick(item) {
  259 + const id = (item && (item.id || item.code)) || ''
  260 + if (!id) return
  261 + const query = '?id=' + encodeURIComponent(id)
  262 + uni.navigateTo({
  263 + url: '/pages/car_request_order/detail' + query
  264 + })
  265 + },
  266 + getDicName: getDicName,
  267 + getCategoryClass(categoryName) {
  268 + if (!categoryName) return ''
  269 + if (categoryName.includes('A') || categoryName.includes('a')) {
  270 + return 'category_A'
  271 + } else if (categoryName.includes('B') || categoryName.includes('b')) {
  272 + return 'category_B'
  273 + } else if (categoryName.includes('C') || categoryName.includes('c')) {
  274 + return 'category_C'
  275 + } else if (categoryName.includes('D') || categoryName.includes('d')) {
  276 + return 'category_D'
  277 + }
  278 + },
  279 + onDeptNameInput(val) {
  280 + this.filterForm.deptName = val
  281 + },
  282 + onWorkshopChange(e) {
  283 + const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ? e.value : '')
  284 + this.filterForm.workshopId = raw
  285 + const match = (this.workshopOptions || []).find(o => String(o.value) === String(raw))
  286 + this.filterForm.workshopIdName = match ? (match.text || '') : ''
  287 + },
  288 + onDateChange(e, model) {
  289 + // 确保同步更新 filterForm,避免数据不同步
  290 + this.filterForm.dateRange = e
  291 + },
  292 +
  293 + }
  294 +}
  295 +</script>
  296 +
  297 +<style lang="scss" scoped>
  298 +.page {
  299 + display: flex;
  300 + flex-direction: column;
  301 + height: 100vh;
  302 +}
  303 +
  304 +.dev-list-fixed {
  305 + position: fixed;
  306 + top: 96rpx;
  307 + left: 0;
  308 + right: 0;
  309 + z-index: 2;
  310 + background: #fff;
  311 +
  312 + .search-row {
  313 + display: flex;
  314 + align-items: center;
  315 + padding: 16rpx 32rpx;
  316 +
  317 + .uni-searchbar {
  318 + padding: 0;
  319 + flex: 1;
  320 + }
  321 +
  322 + .tool-icons {
  323 + display: flex;
  324 +
  325 + .tool-icon {
  326 + width: 48rpx;
  327 + height: 48rpx;
  328 + display: block;
  329 + margin-left: 32rpx;
  330 + }
  331 + }
  332 + }
  333 +
  334 +}
  335 +
  336 +/* 仅当前页覆盖 uni-search-bar 盒子高度 */
  337 +::v-deep .uni-searchbar__box {
  338 + height: 80rpx !important;
  339 + justify-content: start;
  340 +
  341 + .uni-searchbar__box-search-input {
  342 + font-size: 32rpx !important;
  343 + }
  344 +}
  345 +
  346 +.list-box {
  347 + flex: 1;
  348 + padding-top: 140rpx;
  349 +
  350 + &.pad-batch {
  351 + padding-bottom: 144rpx;
  352 + }
  353 +
  354 + .card {
  355 + position: relative;
  356 + }
  357 +
  358 + .card-header {
  359 + margin-bottom: 28rpx;
  360 + position: relative;
  361 +
  362 + .title {
  363 + font-size: 36rpx;
  364 + font-weight: 600;
  365 + line-height: 50rpx;
  366 + color: rgba(0, 0, 0, 0.9);
  367 + width: 578rpx;
  368 + }
  369 +
  370 + .status-box {
  371 + position: absolute;
  372 + top: -32rpx;
  373 + right: -12rpx;
  374 +
  375 + .status {
  376 + display: block;
  377 + height: 48rpx;
  378 + line-height: 48rpx;
  379 + font-weight: 600;
  380 + color: #fff;
  381 + font-size: 24rpx;
  382 + padding: 0 14rpx;
  383 + border-radius: 6rpx;
  384 + margin-bottom: 8rpx;
  385 +
  386 + // 已签收
  387 + &.status_DELIVERED {
  388 + background: #E7E7E7;
  389 + color: rgba(0, 0, 0, 0.9);
  390 + }
  391 +
  392 + // 已发货
  393 + &.status_SHIPMENTS {
  394 + background: #2BA471;
  395 + }
  396 +
  397 + // 未发货
  398 + &.status_UN_SHIPMENTS {
  399 + background: #D54941;
  400 + }
  401 + }
  402 +
  403 + .status2 {
  404 + display: block;
  405 + font-weight: 600;
  406 + line-height: 48rpx;
  407 + height: 48rpx;
  408 + color: #fff;
  409 + font-size: 24rpx;
  410 + padding: 0 14rpx;
  411 + border-radius: 6rpx;
  412 + background: #E7E7E7;
  413 + color: rgba(0, 0, 0, 0.9);
  414 +
  415 + }
  416 +
  417 + }
  418 +
  419 + }
  420 +
  421 + .info-row {
  422 + display: flex;
  423 + align-items: center;
  424 + color: rgba(0, 0, 0, 0.6);
  425 + font-size: 28rpx;
  426 + margin-bottom: 24rpx;
  427 +
  428 + &:last-child {
  429 + margin-bottom: 0;
  430 + }
  431 +
  432 + text {
  433 + width: 60%;
  434 + line-height: 32rpx;
  435 +
  436 + &:last-child {
  437 + color: rgba(0, 0, 0, 0.9);
  438 + width: 40%;
  439 + }
  440 +
  441 + &.category {
  442 + display: inline-block;
  443 + padding: 4rpx 12rpx;
  444 + border-radius: 6rpx;
  445 + font-size: 24rpx;
  446 + width: auto;
  447 +
  448 + &.category_A {
  449 + background: #FFF0ED;
  450 + color: #D54941;
  451 + }
  452 +
  453 + &.category_B {
  454 + background: #FFF1E9;
  455 + color: #E37318;
  456 + }
  457 +
  458 + &.category_C {
  459 + background: #F2F3FF;
  460 + color: $theme-primary;
  461 + }
  462 +
  463 + &.category_D {
  464 + background: #E3F9E9;
  465 + color: #2BA471;
  466 + }
  467 + }
  468 + }
  469 +
  470 + }
  471 +}
  472 +
  473 +.filter-form {
  474 + .form-item {
  475 + margin-bottom: 24rpx;
  476 + }
  477 +
  478 + .label {
  479 + margin-bottom: 20rpx;
  480 + color: rgba(0, 0, 0, 0.9);
  481 + height: 44rpx;
  482 + line-height: 44rpx;
  483 + font-size: 30rpx;
  484 + }
  485 +
  486 + .uni-easyinput {
  487 + border: 1rpx solid #f3f3f3;
  488 + }
  489 +
  490 +}
  491 +
  492 +/* 深度覆盖 uni-data-checkbox(mode=tag)内部的 tag 展示与间距 */
  493 +::v-deep .filter-form .uni-data-checklist .checklist-group {
  494 + .checklist-box {
  495 + &.is--tag {
  496 + width: 212rpx;
  497 + margin-top: 0;
  498 + margin-bottom: 24rpx;
  499 + margin-right: 24rpx;
  500 + height: 80rpx;
  501 + padding: 0;
  502 + border-radius: 12rpx;
  503 + background-color: #f3f3f3;
  504 + border-color: #f3f3f3;
  505 +
  506 + &:nth-child(3n) {
  507 + margin-right: 0;
  508 + }
  509 +
  510 + .checklist-content {
  511 + display: flex;
  512 + justify-content: center;
  513 + }
  514 +
  515 + .checklist-text {
  516 + color: rgba(0, 0, 0, 0.9);
  517 + font-size: 28rpx;
  518 + }
  519 + }
  520 +
  521 + &.is-checked {
  522 + background-color: $theme-primary-plain-bg !important;
  523 + border-color: $theme-primary-plain-bg !important;
  524 +
  525 + .checklist-text {
  526 + color: $theme-primary !important;
  527 + }
  528 + }
  529 + }
  530 +
  531 +}
  532 +</style>
... ...
... ... @@ -393,7 +393,8 @@ export default {
393 393 const v = Number(it && it.quantity)
394 394 return acc + (isNaN(v) ? 0 : v)
395 395 }, 0)
396   - this.form.afterTotalQuantity = sum
  396 + const fixedSum = Number(sum.toFixed(2))
  397 + this.form.afterTotalQuantity = fixedSum
397 398 },
398 399 }
399 400 }
... ... @@ -622,7 +623,6 @@ export default {
622 623 color: rgba(0, 0, 0, 0.9);
623 624 padding-bottom: 16rpx;
624 625 margin-bottom: 24rpx;
625   - ;
626 626 border-bottom: 1px dashed #E7E7E7;
627 627 }
628 628
... ...
... ... @@ -228,7 +228,7 @@ export default {
228 228
229 229 .list-box {
230 230 flex: 1;
231   - padding: 120rpx 0 0;
  231 + padding: 140rpx 0 0;
232 232 }
233 233
234 234 .card {
... ... @@ -250,7 +250,7 @@ export default {
250 250 font-weight: 600;
251 251 position: absolute;
252 252 top: -32rpx;
253   - right: -32rpx;
  253 + right: -12rpx;
254 254 height: 48rpx;
255 255 line-height: 48rpx;
256 256 color: #fff;
... ...
... ... @@ -312,7 +312,8 @@ export default {
312 312 const v = Number(it && it.quantity)
313 313 return acc + (isNaN(v) ? 0 : v)
314 314 }, 0)
315   - this.form.afterTotalQuantity = sum
  315 + const fixedSum = Number(sum.toFixed(2));
  316 + this.form.afterTotalQuantity = fixedSum;
316 317 },
317 318 }
318 319 }
... ... @@ -541,7 +542,6 @@ export default {
541 542 color: rgba(0, 0, 0, 0.9);
542 543 padding-bottom: 16rpx;
543 544 margin-bottom: 24rpx;
544   - ;
545 545 border-bottom: 1px dashed #E7E7E7;
546 546 }
547 547
... ...
... ... @@ -113,8 +113,9 @@
113 113 <template v-slot:footer>
114 114 <uni-easyinput type="digit" v-model="item.quantity" placeholder="请输入数量kg"
115 115 :inputBorder="false"
116   - @input="onNonNegativeNumberInput($event, item, idx, 'quantity')"
117   - @blur="onNonNegativeNumberBlur(item, idx, 'quantity')" />
  116 + @input="onTwoDecimalInput($event, item, idx, 'quantity')"
  117 + @blur="onTwoDecimalBlur(item, idx, 'quantity')"
  118 + />
118 119 </template>
119 120 </uni-list-item>
120 121 <uni-list-item v-if="item.showSalesPrice" title="销售价格">
... ... @@ -380,6 +381,49 @@ export default {
380 381 if (isNaN(n)) item[field] = ''
381 382 if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
382 383 },
  384 + // 限制输入为2位小数
  385 + onTwoDecimalInput(val, item, idx, field) {
  386 + let v = String(val != null ? val : (item && item[field]) || '')
  387 + v = v.replace(/[^0-9.]/g, '')
  388 + v = v.replace(/(\..*)\./g, '$1')
  389 +
  390 + // Restrict to 2 decimal places
  391 + const decimalIndex = v.indexOf('.')
  392 + if (decimalIndex !== -1 && v.length > decimalIndex + 3) {
  393 + v = v.substring(0, decimalIndex + 3)
  394 + }
  395 +
  396 + if (v.startsWith('.')) v = '0' + v
  397 +
  398 + // If the value was modified (truncated or cleaned)
  399 + if (String(val) !== v) {
  400 + // Hack: Temporarily set the dirty value to trigger Vue update mechanism
  401 + // This ensures that when we set the clean value back, Vue detects a change
  402 + item[field] = val
  403 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  404 +
  405 + // Then revert to the clean value asynchronously
  406 + setTimeout(() => {
  407 + item[field] = v
  408 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  409 + }, 0)
  410 + } else {
  411 + item[field] = v
  412 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  413 + }
  414 + },
  415 + onTwoDecimalBlur(item, idx, field) {
  416 + let v = String((item && item[field]) || '')
  417 + const num = Number(v)
  418 + if (isNaN(num) || num < 0) {
  419 + item[field] = '0'
  420 + } else {
  421 + if (v.endsWith('.')) {
  422 + item[field] = v.slice(0, -1)
  423 + }
  424 + }
  425 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  426 + },
383 427 toggleViewCollapse() {
384 428 this.collapsedView = !this.collapsedView
385 429 },
... ... @@ -729,7 +773,6 @@ export default {
729 773 color: rgba(0, 0, 0, 0.9);
730 774 padding-bottom: 16rpx;
731 775 margin-bottom: 24rpx;
732   - ;
733 776 border-bottom: 1px dashed #E7E7E7;
734 777 }
735 778
... ... @@ -846,7 +889,6 @@ export default {
846 889 color: rgba(0, 0, 0, 0.9);
847 890 padding-bottom: 16rpx;
848 891 margin-bottom: 24rpx;
849   - ;
850 892 border-bottom: 1px dashed #E7E7E7;
851 893 }
852 894
... ...
... ... @@ -546,4 +546,7 @@ export default {
546 546 color: rgba(0, 0, 0, 0.6);
547 547 font-size: 32rpx;
548 548 }
  549 +.upload-row {
  550 + margin-top: 20rpx;
  551 +}
549 552 </style>
\ No newline at end of file
... ...
... ... @@ -330,7 +330,7 @@ export default {
330 330 font-weight: 600;
331 331 position: absolute;
332 332 top: -36rpx;
333   - right: -32rpx;
  333 + right: -12rpx;
334 334 height: 48rpx;
335 335 line-height: 48rpx;
336 336 color: #fff;
... ... @@ -366,19 +366,19 @@ export default {
366 366 }
367 367 }
368 368
369   -.filter-form {
  369 +.filter-form {
370 370 .form-item { margin-bottom: 24rpx; }
371   - .label {
372   - margin-bottom: 20rpx;
  371 + .label {
  372 + margin-bottom: 20rpx;
373 373 color: rgba(0,0,0,0.9);
374 374 height: 44rpx;
375 375 line-height: 44rpx;
376 376 font-size: 30rpx;
377 377 }
378   - .fake-select {
379   - height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
  378 + .fake-select {
  379 + height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
380 380 .placeholder { color: #999; }
381 381 .value { color: #333; }
382 382 }
383 383 }
384   -</style>
\ No newline at end of file
  384 +</style>
... ...
... ... @@ -638,4 +638,7 @@ export default {
638 638 color: rgba(0, 0, 0, 0.6);
639 639 font-size: 32rpx;
640 640 }
  641 +.upload-row {
  642 + margin-top: 20rpx;
  643 +}
641 644 </style>
\ No newline at end of file
... ...
... ... @@ -331,7 +331,7 @@ export default {
331 331 font-weight: 600;
332 332 position: absolute;
333 333 top: -36rpx;
334   - right: -32rpx;
  334 + right: -12rpx;
335 335 height: 48rpx;
336 336 line-height: 48rpx;
337 337 color: #fff;
... ... @@ -380,19 +380,19 @@ export default {
380 380 }
381 381 }
382 382
383   -.filter-form {
  383 +.filter-form {
384 384 .form-item { margin-bottom: 24rpx; }
385   - .label {
386   - margin-bottom: 20rpx;
  385 + .label {
  386 + margin-bottom: 20rpx;
387 387 color: rgba(0,0,0,0.9);
388 388 height: 44rpx;
389 389 line-height: 44rpx;
390 390 font-size: 30rpx;
391 391 }
392   - .fake-select {
393   - height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
  392 + .fake-select {
  393 + height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
394 394 .placeholder { color: #999; }
395 395 .value { color: #333; }
396 396 }
397 397 }
398   -</style>
\ No newline at end of file
  398 +</style>
... ...
... ... @@ -650,4 +650,7 @@ export default {
650 650 color: rgba(0, 0, 0, 0.6);
651 651 font-size: 32rpx;
652 652 }
  653 +.upload-row {
  654 + margin-top: 20rpx;
  655 +}
653 656 </style>
\ No newline at end of file
... ...
... ... @@ -63,7 +63,7 @@
63 63 <view class="info-row" v-if="item.status === 'STANDARD' || item.status === 'FORMAL'">
64 64 <text>{{ item.status === 'STANDARD' ? '标准合同' : '正式合同' }}规范性审核状态</text>
65 65 <span v-if="item.status === 'STANDARD' ? item.standardApprovedName : item.formalApprovedName" class="info-status" :style="getStatusCss(item.status === 'STANDARD' ? item.standardApprovedName : item.formalApprovedName)">{{ item.status === 'STANDARD' ? item.standardApprovedName : item.formalApprovedName }}</span>
66   - <span v-else>-</span>
  66 + <span v-else>-</span>
67 67 </view>
68 68 <view class="info-row">
69 69 <text>订货日期</text><text>{{ item.orderDate }}</text>
... ... @@ -333,7 +333,7 @@ export default {
333 333 font-weight: 600;
334 334 position: absolute;
335 335 top: -36rpx;
336   - right: -32rpx;
  336 + right: -12rpx;
337 337 height: 48rpx;
338 338 line-height: 48rpx;
339 339 color: #fff;
... ... @@ -382,19 +382,19 @@ export default {
382 382 }
383 383 }
384 384
385   -.filter-form {
  385 +.filter-form {
386 386 .form-item { margin-bottom: 24rpx; }
387   - .label {
388   - margin-bottom: 20rpx;
  387 + .label {
  388 + margin-bottom: 20rpx;
389 389 color: rgba(0,0,0,0.9);
390 390 height: 44rpx;
391 391 line-height: 44rpx;
392 392 font-size: 30rpx;
393 393 }
394   - .fake-select {
395   - height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
  394 + .fake-select {
  395 + height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
396 396 .placeholder { color: #999; }
397 397 .value { color: #333; }
398 398 }
399 399 }
400   -</style>
\ No newline at end of file
  400 +</style>
... ...
... ... @@ -282,7 +282,7 @@ export default {
282 282 font-weight: 600;
283 283 position: absolute;
284 284 top: -36rpx;
285   - right: -32rpx;
  285 + right: -12rpx;
286 286 height: 48rpx;
287 287 line-height: 48rpx;
288 288 color: #fff;
... ... @@ -402,4 +402,4 @@ export default {
402 402 }
403 403
404 404 }
405   -</style>
\ No newline at end of file
  405 +</style>
... ...
... ... @@ -516,4 +516,7 @@ export default {
516 516 color: rgba(0, 0, 0, 0.6);
517 517 font-size: 32rpx;
518 518 }
  519 +.upload-row {
  520 + margin-top: 20rpx;
  521 +}
519 522 </style>
\ No newline at end of file
... ...
... ... @@ -330,7 +330,7 @@ export default {
330 330 font-weight: 600;
331 331 position: absolute;
332 332 top: -36rpx;
333   - right: -32rpx;
  333 + right: -12rpx;
334 334 height: 48rpx;
335 335 line-height: 48rpx;
336 336 color: #fff;
... ... @@ -379,19 +379,19 @@ export default {
379 379 }
380 380 }
381 381
382   -.filter-form {
  382 +.filter-form {
383 383 .form-item { margin-bottom: 24rpx; }
384   - .label {
385   - margin-bottom: 20rpx;
  384 + .label {
  385 + margin-bottom: 20rpx;
386 386 color: rgba(0,0,0,0.9);
387 387 height: 44rpx;
388 388 line-height: 44rpx;
389 389 font-size: 30rpx;
390 390 }
391   - .fake-select {
392   - height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
  391 + .fake-select {
  392 + height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
393 393 .placeholder { color: #999; }
394 394 .value { color: #333; }
395 395 }
396 396 }
397   -</style>
\ No newline at end of file
  397 +</style>
... ...
... ... @@ -545,4 +545,7 @@ export default {
545 545 background: $theme-primary;
546 546 color: #fff;
547 547 }
  548 +.upload-row {
  549 + margin-top: 20rpx;
  550 +}
548 551 </style>
... ...
... ... @@ -327,7 +327,7 @@ export default {
327 327 font-weight: 600;
328 328 position: absolute;
329 329 top: -36rpx;
330   - right: -32rpx;
  330 + right: -12rpx;
331 331 height: 48rpx;
332 332 line-height: 48rpx;
333 333 color: #fff;
... ... @@ -376,19 +376,19 @@ export default {
376 376 }
377 377 }
378 378
379   -.filter-form {
  379 +.filter-form {
380 380 .form-item { margin-bottom: 24rpx; }
381   - .label {
382   - margin-bottom: 20rpx;
  381 + .label {
  382 + margin-bottom: 20rpx;
383 383 color: rgba(0,0,0,0.9);
384 384 height: 44rpx;
385 385 line-height: 44rpx;
386 386 font-size: 30rpx;
387 387 }
388   - .fake-select {
389   - height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
  388 + .fake-select {
  389 + height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
390 390 .placeholder { color: #999; }
391 391 .value { color: #333; }
392 392 }
393 393 }
394   -</style>
\ No newline at end of file
  394 +</style>
... ...
... ... @@ -599,4 +599,7 @@ export default {
599 599 color: rgba(0, 0, 0, 0.6);
600 600 font-size: 32rpx;
601 601 }
  602 +.upload-row {
  603 + margin-top: 20rpx;
  604 +}
602 605 </style>
... ...
... ... @@ -333,7 +333,7 @@ export default {
333 333 font-weight: 600;
334 334 position: absolute;
335 335 top: -36rpx;
336   - right: -32rpx;
  336 + right: -12rpx;
337 337 height: 48rpx;
338 338 line-height: 48rpx;
339 339 color: #fff;
... ... @@ -382,19 +382,19 @@ export default {
382 382 }
383 383 }
384 384
385   -.filter-form {
  385 +.filter-form {
386 386 .form-item { margin-bottom: 24rpx; }
387   - .label {
388   - margin-bottom: 20rpx;
  387 + .label {
  388 + margin-bottom: 20rpx;
389 389 color: rgba(0,0,0,0.9);
390 390 height: 44rpx;
391 391 line-height: 44rpx;
392 392 font-size: 30rpx;
393 393 }
394   - .fake-select {
395   - height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
  394 + .fake-select {
  395 + height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
396 396 .placeholder { color: #999; }
397 397 .value { color: #333; }
398 398 }
399 399 }
400   -</style>
\ No newline at end of file
  400 +</style>
... ...
... ... @@ -299,7 +299,7 @@ export default {
299 299 font-weight: 600;
300 300 position: absolute;
301 301 top: -36rpx;
302   - right: -32rpx;
  302 + right: -12rpx;
303 303 height: 48rpx;
304 304 line-height: 48rpx;
305 305 color: #fff;
... ... @@ -418,4 +418,4 @@ export default {
418 418 }
419 419
420 420 }
421   -</style>
\ No newline at end of file
  421 +</style>
... ...
... ... @@ -632,4 +632,7 @@ export default {
632 632 color: rgba(0, 0, 0, 0.6);
633 633 font-size: 32rpx;
634 634 }
  635 +.upload-row {
  636 + margin-top: 20rpx;
  637 +}
635 638 </style>
\ No newline at end of file
... ...
... ... @@ -63,7 +63,7 @@
63 63 <view class="info-row" v-if="item.status === 'STANDARD' || item.status === 'FORMAL'">
64 64 <text>{{ item.status === 'STANDARD' ? '标准合同' : '正式合同' }}规范性审核状态</text>
65 65 <span v-if="item.status === 'STANDARD' ? item.standardApprovedName : item.formalApprovedName" class="info-status" :style="getStatusCss(item.status === 'STANDARD' ? item.standardApprovedName : item.formalApprovedName)">{{ item.status === 'STANDARD' ? item.standardApprovedName : item.formalApprovedName }}</span>
66   - <span v-else>-</span>
  66 + <span v-else>-</span>
67 67 </view>
68 68 <view class="info-row">
69 69 <text>订货日期</text><text>{{ item.orderDate }}</text>
... ... @@ -333,7 +333,7 @@ export default {
333 333 font-weight: 600;
334 334 position: absolute;
335 335 top: -36rpx;
336   - right: -32rpx;
  336 + right: -12rpx;
337 337 height: 48rpx;
338 338 line-height: 48rpx;
339 339 color: #fff;
... ... @@ -382,19 +382,19 @@ export default {
382 382 }
383 383 }
384 384
385   -.filter-form {
  385 +.filter-form {
386 386 .form-item { margin-bottom: 24rpx; }
387   - .label {
388   - margin-bottom: 20rpx;
  387 + .label {
  388 + margin-bottom: 20rpx;
389 389 color: rgba(0,0,0,0.9);
390 390 height: 44rpx;
391 391 line-height: 44rpx;
392 392 font-size: 30rpx;
393 393 }
394   - .fake-select {
395   - height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
  394 + .fake-select {
  395 + height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
396 396 .placeholder { color: #999; }
397 397 .value { color: #333; }
398 398 }
399 399 }
400   -</style>
\ No newline at end of file
  400 +</style>
... ...
... ... @@ -8,7 +8,7 @@
8 8 </template>
9 9 <template v-slot:footer>
10 10 <view class="serial-number-row">
11   - <uni-easyinput v-model="form.serialNumber" placeholder="自动生成编号" :inputBorder="false" disabled />
  11 + <text class="readonly-text value-code">{{ form.serialNumber }}</text>
12 12 <button class="generate-btn" @click="loadSerialNumber">点此生成</button>
13 13 </view>
14 14 </template>
... ... @@ -808,4 +808,8 @@ export default {
808 808 white-space: pre-wrap;
809 809 word-break: break-all;
810 810 }
  811 +.value-code {
  812 + width: 260rpx;
  813 + text-align: left;
  814 +}
811 815 </style>
... ...
... ... @@ -8,7 +8,7 @@
8 8 </template>
9 9 <template v-slot:footer>
10 10 <view class="serial-number-row">
11   - <uni-easyinput v-model="form.serialNumber" placeholder="自动生成编号" :inputBorder="false" disabled />
  11 + <text class="readonly-text">{{ form.serialNumber }}</text>
12 12 </view>
13 13 </template>
14 14 </uni-list-item>
... ...
... ... @@ -449,6 +449,7 @@ export default {
449 449 font-size: 28rpx;
450 450 color: rgba(0, 0, 0, 0.9);
451 451 text-align: right;
  452 + word-break: break-all;
452 453
453 454 &.act {
454 455 color: $theme-primary;
... ...
... ... @@ -6,8 +6,7 @@
6 6 cancelButton="none" bgColor="#F3F3F3" textColor="rgba(0,0,0,0.4)" @confirm="search"
7 7 @input="onSearchInput" />
8 8 <view class="tool-icons">
9   - <image v-if="$auth.hasPermi('customer-credit-manage:customer-credit-plan:add')" class="tool-icon"
10   - src="/static/images/dev_manage/add_icon.png" @click="onAdd" />
  9 + <image v-if="$auth.hasPermi('customer-credit-manage:customer-credit-plan:add')" class="tool-icon" src="/static/images/dev_manage/add_icon.png" @click="onAdd" />
11 10 <image class="tool-icon" src="/static/images/dev_manage/filter_icon.png" @click="openFilter" />
12 11 </view>
13 12 </view>
... ... @@ -23,24 +22,22 @@
23 22 <view class="card-header">
24 23 <text class="title omit2">{{ item.companyName }}</text>
25 24 <view class="status-box">
26   - <text :class="['status', `status_${item.status}`]">{{ getDicName('AUDIT_STATUS',
27   - item.status, dicOptions.AUDIT_STATUS) }}</text>
28   - <text v-if="item.frozenStatus === '冻结'" :class="['status2']">{{ item.frozenStatus ===
29   - '冻结' ? '已冻结' : '' }}</text>
  25 + <text
  26 + :class="['status', `status_${item.status}`]">{{ getDicName('AUDIT_STATUS', item.status, dicOptions.AUDIT_STATUS) }}</text>
  27 + <text
  28 + v-if="item.frozenStatus === '冻结'"
  29 + :class="['status2']">{{ item.frozenStatus === '冻结' ? '已冻结' : '' }}</text>
30 30 </view>
31 31 </view>
32 32 <view class="info-row">
33   - <text>企业类型</text><text>{{ getDicName('ENTERPRISE_TYPE', item.enterpriseType,
34   - dicOptions.ENTERPRISE_TYPE) || '-' }}</text>
  33 + <text>企业类型</text><text>{{ getDicName('ENTERPRISE_TYPE', item.enterpriseType, dicOptions.ENTERPRISE_TYPE) || '-' }}</text>
35 34 </view>
36 35 <view class="info-row">
37 36 <text>区域</text><text>{{ item.regionName || '-' }}</text>
38 37 </view>
39 38 <view class="info-row">
40 39 <text>客户分类</text><text
41   - :class="[item.companySuggestedCategory ? 'category' : '', getCategoryClass(getDicName('CUSTOMER_CATEGORY', item.companySuggestedCategory, dicOptions.CUSTOMER_CATEGORY))]">{{
42   - getDicName('CUSTOMER_CATEGORY', item.companySuggestedCategory,
43   - dicOptions.CUSTOMER_CATEGORY) || '-' }}</text>
  40 + :class="[item.companySuggestedCategory ? 'category' : '', getCategoryClass(getDicName('CUSTOMER_CATEGORY', item.companySuggestedCategory, dicOptions.CUSTOMER_CATEGORY))]">{{ getDicName('CUSTOMER_CATEGORY', item.companySuggestedCategory, dicOptions.CUSTOMER_CATEGORY) || '-' }}</text>
44 41 </view>
45 42 <view class="info-row">
46 43 <text>登记日期</text><text>{{ item.registerDate || '-' }}</text>
... ... @@ -70,8 +67,7 @@
70 67 </view>
71 68 <view class="form-item">
72 69 <view class="label">登记日期</view>
73   - <uni-datetime-picker type="daterange" v-model="model.dateRange" start="2023-01-01"
74   - @change="onDateChange($event, model)" />
  70 + <uni-datetime-picker type="daterange" v-model="model.dateRange" start="2023-01-01" />
75 71 </view>
76 72 </view>
77 73 </template>
... ... @@ -80,497 +76,491 @@
80 76 </template>
81 77
82 78 <script>
83   -import CardList from '@/components/card/index.vue'
84   -import FilterModal from '@/components/filter/index.vue'
85   -import SingleSelectSheet from '@/components/single-select/index.vue'
86   -import {
87   - queryApi
88   -} from '@/api/credit_manage.js'
89   -import {
90   - getDicByCodes
91   -} from '@/utils/dic'
92   -import {
93   - getDicName
94   -} from '@/utils/dic.js'
95   -
96   -export default {
97   - components: {
98   - CardList,
99   - FilterModal,
100   - SingleSelectSheet
101   - },
102   - data() {
103   - return {
104   - searchKeyword: '',
105   - searchKeywordDebounced: '',
106   - tabs: [],
107   - // 给到 card 的筛选值
108   - query: {
109   - status: '',
110   - companySuggestedCategory: '',
111   - dateRange: []
112   - },
113   - extraParams: {},
114   -
115   - // 批量选择
116   - rowKey: 'id',
117   - currentItems: [],
118   -
119   - // 筛选弹框
120   - filterVisible: false,
121   - filterForm: {
122   - status: '',
123   - companySuggestedCategory: '',
124   - dateRange: []
125   - },
126   - dicOptions: {
127   - CUSTOMER_CATEGORY: [],
128   - AUDIT_STATUS: [],
129   - ENTERPRISE_TYPE: [],
130   - CREDIT_ZONE: []
131   - },
132   - statusLocal: [],
133   - categoryLocal: []
134   - }
135   - },
136   - computed: {
137   - extraCombined() {
  79 + import CardList from '@/components/card/index.vue'
  80 + import FilterModal from '@/components/filter/index.vue'
  81 + import SingleSelectSheet from '@/components/single-select/index.vue'
  82 + import {
  83 + queryApi
  84 + } from '@/api/credit_manage.js'
  85 + import {
  86 + getDicByCodes
  87 + } from '@/utils/dic'
  88 + import {
  89 + getDicName
  90 + } from '@/utils/dic.js'
  91 +
  92 + export default {
  93 + components: {
  94 + CardList,
  95 + FilterModal,
  96 + SingleSelectSheet
  97 + },
  98 + data() {
138 99 return {
139   - companyName: this.searchKeywordDebounced || undefined
  100 + searchKeyword: '',
  101 + searchKeywordDebounced: '',
  102 + tabs: [],
  103 + // 给到 card 的筛选值
  104 + query: {
  105 + status: '',
  106 + companySuggestedCategory: '',
  107 + dateRange: []
  108 + },
  109 + extraParams: {},
  110 +
  111 + // 批量选择
  112 + rowKey: 'id',
  113 + currentItems: [],
  114 +
  115 + // 筛选弹框
  116 + filterVisible: false,
  117 + filterForm: {
  118 + status: '',
  119 + companySuggestedCategory: '',
  120 + dateRange: []
  121 + },
  122 + dicOptions: {
  123 + CUSTOMER_CATEGORY: [],
  124 + AUDIT_STATUS: [],
  125 + ENTERPRISE_TYPE: [],
  126 + CREDIT_ZONE: []
  127 + },
  128 + statusLocal: [],
  129 + categoryLocal: []
140 130 }
141   - }
142   - },
143   - watch: {
144   - extraCombined: {
145   - deep: true,
146   - handler(v) {
147   - this.extraParams = v
148   - },
149   - immediate: true
150   - },
151   -
152   - },
153   - created() {
154   - this.loadAllDicData()
155   - },
156   - onLoad() { },
157   - // 页面触底兜底:当页面自身滚动到底部时,转调卡片组件加载更多
158   - onReachBottom() {
159   - if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) {
160   - this.$refs.cardRef.onLoadMore()
161   - }
162   - },
163   - beforeDestroy() {
164   - if (this.searchDebounceTimer) {
165   - clearTimeout(this.searchDebounceTimer)
166   - this.searchDebounceTimer = null
167   - }
168   - },
169   - methods: {
170   - onCardLoaded({
171   - items
172   - }) {
173   - this.currentItems = items
174   - },
175   - onCardError() {
176   - uni.showToast({
177   - title: '列表加载失败',
178   - icon: 'none'
179   - })
180 131 },
181   - // 输入实时搜索:1200ms 防抖,仅在停止输入超过阈值后刷新
182   - onSearchInput(val) {
183   - if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer)
184   - this.searchDebounceTimer = setTimeout(() => {
185   - this.searchKeywordDebounced = this.searchKeyword
186   - this.searchDebounceTimer = null
187   - }, 1200)
188   - },
189   - // uni-search-bar 确认搜索:更新关键字并触发 CardList 刷新
190   - search(e) {
191   - const val = e && e.value != null ? e.value : this.searchKeyword
192   - this.searchKeyword = val
193   - this.searchKeywordDebounced = val
194   - },
195   - onAdd() {
196   - uni.navigateTo({
197   - url: '/pages/credit_manage/add'
198   - })
  132 + computed: {
  133 + extraCombined() {
  134 + return {
  135 + companyName: this.searchKeywordDebounced || undefined
  136 + }
  137 + }
199 138 },
200   - openFilter() {
201   - this.filterVisible = true
  139 + watch: {
  140 + extraCombined: {
  141 + deep: true,
  142 + handler(v) {
  143 + this.extraParams = v
  144 + },
  145 + immediate: true
  146 + },
  147 +
202 148 },
203   - onFilterReset(payload) {
204   - this.filterForm = payload
  149 + created() {
  150 + this.loadAllDicData()
205 151 },
206   - onFilterConfirm(payload) {
207   - if ((payload.status === '' || payload.status == null) && this.filterForm.status !== '') {
208   - payload.status = this.filterForm.status
209   - }
210   - if ((payload.companySuggestedCategory === '' || payload.companySuggestedCategory == null) && this
211   - .filterForm
212   - .companySuggestedCategory !== '') {
213   - payload.companySuggestedCategory = this.filterForm.companySuggestedCategory
  152 + onLoad() {},
  153 + // 页面触底兜底:当页面自身滚动到底部时,转调卡片组件加载更多
  154 + onReachBottom() {
  155 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) {
  156 + this.$refs.cardRef.onLoadMore()
214 157 }
215   - this.query = {
216   - ...payload
217   - }
218   - },
219   - onStatusChange(e) {
220   - const raw = e && e.detail && e.detail.value !== undefined ?
221   - e.detail.value :
222   - (e && e.value !== undefined ? e.value : '')
223   - this.filterForm.status = raw
224 158 },
225   - onCategoryChange(e) {
226   - const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ?
227   - e.value : '')
228   - this.filterForm.companySuggestedCategory = raw
229   - },
230   - onDateChange(e, model) {
231   - // 确保同步更新 filterForm,避免数据不同步
232   - this.filterForm.dateRange = e
  159 + beforeDestroy() {
  160 + if (this.searchDebounceTimer) {
  161 + clearTimeout(this.searchDebounceTimer)
  162 + this.searchDebounceTimer = null
  163 + }
233 164 },
234   - // 列表接口(真实请求)
235   - fetchList({
236   - pageIndex,
237   - pageSize,
238   - query,
239   - extra
240   - }) {
241   - const params = {
  165 + methods: {
  166 + onCardLoaded({
  167 + items
  168 + }) {
  169 + this.currentItems = items
  170 + },
  171 + onCardError() {
  172 + uni.showToast({
  173 + title: '列表加载失败',
  174 + icon: 'none'
  175 + })
  176 + },
  177 + // 输入实时搜索:1200ms 防抖,仅在停止输入超过阈值后刷新
  178 + onSearchInput(val) {
  179 + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer)
  180 + this.searchDebounceTimer = setTimeout(() => {
  181 + this.searchKeywordDebounced = this.searchKeyword
  182 + this.searchDebounceTimer = null
  183 + }, 1200)
  184 + },
  185 + // uni-search-bar 确认搜索:更新关键字并触发 CardList 刷新
  186 + search(e) {
  187 + const val = e && e.value != null ? e.value : this.searchKeyword
  188 + this.searchKeyword = val
  189 + this.searchKeywordDebounced = val
  190 + },
  191 + onAdd() {
  192 + uni.navigateTo({
  193 + url: '/pages/credit_manage/add'
  194 + })
  195 + },
  196 + openFilter() {
  197 + this.filterVisible = true
  198 + },
  199 + onFilterReset(payload) {
  200 + this.filterForm = payload
  201 + },
  202 + onFilterConfirm(payload) {
  203 + if ((payload.status === '' || payload.status == null) && this.filterForm.status !== '') {
  204 + payload.status = this.filterForm.status
  205 + }
  206 + if ((payload.companySuggestedCategory === '' || payload.companySuggestedCategory == null) && this
  207 + .filterForm
  208 + .companySuggestedCategory !== '') {
  209 + payload.companySuggestedCategory = this.filterForm.companySuggestedCategory
  210 + }
  211 + this.query = {
  212 + ...payload
  213 + }
  214 + },
  215 + onStatusChange(e) {
  216 + const raw = e && e.detail && e.detail.value !== undefined ?
  217 + e.detail.value :
  218 + (e && e.value !== undefined ? e.value : '')
  219 + this.filterForm.status = raw
  220 + },
  221 + onCategoryChange(e) {
  222 + const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ?
  223 + e.value : '')
  224 + this.filterForm.companySuggestedCategory = raw
  225 + },
  226 +
  227 + // 列表接口(真实请求)
  228 + fetchList({
242 229 pageIndex,
243 230 pageSize,
244   - ...extra,
245   - ...query
246   - }
247   - if (Array.isArray(params.dateRange) && params.dateRange.length === 2) {
248   - params.registerDateStart = params.dateRange[0] + ' 00:00:00'
249   - params.registerDateEnd = params.dateRange[1] + ' 23:59:59'
250   - delete params.dateRange
251   - }
252   - if (this.searchKeywordDebounced) {
253   - params.companyName = this.searchKeywordDebounced
254   - }
255   - return queryApi(params)
256   - .then(res => {
257   - const _data = res.data || {};
258   - const records = _data.datas || [];
259   - const totalCount = _data.totalCount || 0;
260   - const hasNext = _data.hasNext || false
261   - return {
262   - records,
263   - totalCount,
264   - hasNext
  231 + query,
  232 + extra
  233 + }) {
  234 + const params = {
  235 + pageIndex,
  236 + pageSize,
  237 + ...extra,
  238 + ...query
  239 + }
  240 + if (Array.isArray(params.dateRange) && params.dateRange.length === 2) {
  241 + params.registerDateStart = params.dateRange[0] + ' 00:00:00'
  242 + params.registerDateEnd = params.dateRange[1] + ' 23:59:59'
  243 + delete params.dateRange
  244 + }
  245 + if (this.searchKeywordDebounced) {
  246 + params.companyName = this.searchKeywordDebounced
  247 + }
  248 + return queryApi(params)
  249 + .then(res => {
  250 + const _data = res.data || {};
  251 + const records = _data.datas || [];
  252 + const totalCount = _data.totalCount || 0;
  253 + const hasNext = _data.hasNext || false
  254 + return {
  255 + records,
  256 + totalCount,
  257 + hasNext
  258 + }
  259 + })
  260 + .catch(err => {
  261 + console.error('fetchList error', err)
  262 + this.onCardError()
  263 + return {
  264 + records: [],
  265 + totalCount: 0,
  266 + hasNext: false
  267 + }
  268 + })
  269 + },
  270 + loadAllDicData() {
  271 + const dicCodes = ['CUSTOMER_CATEGORY', 'AUDIT_STATUS', 'ENTERPRISE_TYPE', 'CREDIT_ZONE']
  272 + return getDicByCodes(dicCodes).then(results => {
  273 + this.dicOptions.CUSTOMER_CATEGORY = results.CUSTOMER_CATEGORY.data || []
  274 + this.dicOptions.AUDIT_STATUS = results.AUDIT_STATUS.data || []
  275 + this.dicOptions.ENTERPRISE_TYPE = results.ENTERPRISE_TYPE.data || []
  276 + this.dicOptions.CREDIT_ZONE = results.CREDIT_ZONE.data || [];
  277 + this.categoryLocal = (this.dicOptions.CUSTOMER_CATEGORY || []).map(it => ({
  278 + value: it.code,
  279 + text: it.name
  280 + }))
  281 + this.statusLocal = (this.dicOptions.AUDIT_STATUS || []).map(it => ({
  282 + value: it.code,
  283 + text: it.name
  284 + }))
  285 + }).catch(() => {
  286 + this.dicOptions = {
  287 + CUSTOMER_CATEGORY: [],
  288 + AUDIT_STATUS: [],
  289 + ENTERPRISE_TYPE: [],
  290 + CREDIT_ZONE: []
265 291 }
  292 + this.categoryLocal = []
  293 + this.statusLocal = []
266 294 })
267   - .catch(err => {
268   - console.error('fetchList error', err)
269   - this.onCardError()
270   - return {
271   - records: [],
272   - totalCount: 0,
273   - hasNext: false
274   - }
  295 + },
  296 + onCardClick(item) {
  297 + const id = (item && (item.id || item.code)) || ''
  298 + if (!id) return
  299 + const query = '?id=' + encodeURIComponent(id)
  300 + uni.navigateTo({
  301 + url: '/pages/credit_manage/detail' + query
275 302 })
276   - },
277   - loadAllDicData() {
278   - const dicCodes = ['CUSTOMER_CATEGORY', 'AUDIT_STATUS', 'ENTERPRISE_TYPE', 'CREDIT_ZONE']
279   - return getDicByCodes(dicCodes).then(results => {
280   - this.dicOptions.CUSTOMER_CATEGORY = results.CUSTOMER_CATEGORY.data || []
281   - this.dicOptions.AUDIT_STATUS = results.AUDIT_STATUS.data || []
282   - this.dicOptions.ENTERPRISE_TYPE = results.ENTERPRISE_TYPE.data || []
283   - this.dicOptions.CREDIT_ZONE = results.CREDIT_ZONE.data || [];
284   - this.categoryLocal = (this.dicOptions.CUSTOMER_CATEGORY || []).map(it => ({
285   - value: it.code,
286   - text: it.name
287   - }))
288   - this.statusLocal = (this.dicOptions.AUDIT_STATUS || []).map(it => ({
289   - value: it.code,
290   - text: it.name
291   - }))
292   - }).catch(() => {
293   - this.dicOptions = {
294   - CUSTOMER_CATEGORY: [],
295   - AUDIT_STATUS: [],
296   - ENTERPRISE_TYPE: [],
297   - CREDIT_ZONE: []
  303 + },
  304 + getDicName: getDicName,
  305 + getCategoryClass(categoryName) {
  306 + if (!categoryName) return ''
  307 + if (categoryName.includes('A') || categoryName.includes('a')) {
  308 + return 'category_A'
  309 + } else if (categoryName.includes('B') || categoryName.includes('b')) {
  310 + return 'category_B'
  311 + } else if (categoryName.includes('C') || categoryName.includes('c')) {
  312 + return 'category_C'
  313 + } else if (categoryName.includes('D') || categoryName.includes('d')) {
  314 + return 'category_D'
298 315 }
299   - this.categoryLocal = []
300   - this.statusLocal = []
301   - })
302   - },
303   - onCardClick(item) {
304   - const id = (item && (item.id || item.code)) || ''
305   - if (!id) return
306   - const query = '?id=' + encodeURIComponent(id)
307   - uni.navigateTo({
308   - url: '/pages/credit_manage/detail' + query
309   - })
310   - },
311   - getDicName: getDicName,
312   - getCategoryClass(categoryName) {
313   - if (!categoryName) return ''
314   - if (categoryName.includes('A') || categoryName.includes('a')) {
315   - return 'category_A'
316   - } else if (categoryName.includes('B') || categoryName.includes('b')) {
317   - return 'category_B'
318   - } else if (categoryName.includes('C') || categoryName.includes('c')) {
319   - return 'category_C'
320   - } else if (categoryName.includes('D') || categoryName.includes('d')) {
321   - return 'category_D'
322 316 }
323   - }
324 317
  318 + }
325 319 }
326   -}
327 320 </script>
328 321
329 322 <style lang="scss" scoped>
330   -.page {
331   - display: flex;
332   - flex-direction: column;
333   - height: 100vh;
334   -}
335   -
336   -.dev-list-fixed {
337   - position: fixed;
338   - top: 96rpx;
339   - left: 0;
340   - right: 0;
341   - z-index: 2;
342   - background: #fff;
343   -
344   - .search-row {
  323 + .page {
345 324 display: flex;
346   - align-items: center;
347   - padding: 16rpx 32rpx;
  325 + flex-direction: column;
  326 + height: 100vh;
  327 + }
348 328
349   - .uni-searchbar {
350   - padding: 0;
351   - flex: 1;
352   - }
  329 + .dev-list-fixed {
  330 + position: fixed;
  331 + top: 96rpx;
  332 + left: 0;
  333 + right: 0;
  334 + z-index: 2;
  335 + background: #fff;
353 336
354   - .tool-icons {
  337 + .search-row {
355 338 display: flex;
  339 + align-items: center;
  340 + padding: 16rpx 32rpx;
356 341
357   - .tool-icon {
358   - width: 48rpx;
359   - height: 48rpx;
360   - display: block;
361   - margin-left: 32rpx;
  342 + .uni-searchbar {
  343 + padding: 0;
  344 + flex: 1;
362 345 }
363   - }
364   - }
365 346
366   -}
  347 + .tool-icons {
  348 + display: flex;
367 349
368   -/* 仅当前页覆盖 uni-search-bar 盒子高度 */
369   -::v-deep .uni-searchbar__box {
370   - height: 80rpx !important;
371   - justify-content: start;
  350 + .tool-icon {
  351 + width: 48rpx;
  352 + height: 48rpx;
  353 + display: block;
  354 + margin-left: 32rpx;
  355 + }
  356 + }
  357 + }
372 358
373   - .uni-searchbar__box-search-input {
374   - font-size: 32rpx !important;
375 359 }
376   -}
377 360
378   -.list-box {
379   - flex: 1;
380   - padding-top: 132rpx;
  361 + /* 仅当前页覆盖 uni-search-bar 盒子高度 */
  362 + ::v-deep .uni-searchbar__box {
  363 + height: 80rpx !important;
  364 + justify-content: start;
381 365
382   - &.pad-batch {
383   - padding-bottom: 144rpx;
  366 + .uni-searchbar__box-search-input {
  367 + font-size: 32rpx !important;
  368 + }
384 369 }
385 370
386   - .card {
387   - position: relative;
388   - }
  371 + .list-box {
  372 + flex: 1;
  373 + padding-top: 140rpx;
389 374
390   - .card-header {
391   - margin-bottom: 28rpx;
392   - position: relative;
  375 + &.pad-batch {
  376 + padding-bottom: 144rpx;
  377 + }
393 378
394   - .title {
395   - font-size: 36rpx;
396   - font-weight: 600;
397   - line-height: 50rpx;
398   - color: rgba(0, 0, 0, 0.9);
399   - width: 578rpx;
  379 + .card {
  380 + position: relative;
400 381 }
401 382
402   - .status-box {
403   - position: absolute;
404   - top: -32rpx;
405   - right: -32rpx;
  383 + .card-header {
  384 + margin-bottom: 28rpx;
  385 + position: relative;
406 386
407   - .status {
408   - display: block;
409   - height: 48rpx;
410   - line-height: 48rpx;
  387 + .title {
  388 + font-size: 36rpx;
411 389 font-weight: 600;
412   - color: #fff;
413   - font-size: 24rpx;
414   - padding: 0 14rpx;
415   - border-radius: 6rpx;
416   - margin-bottom: 8rpx;
417   -
418   - &.status_AUDIT {
419   - background: $theme-primary;
420   - }
  390 + line-height: 50rpx;
  391 + color: rgba(0,0,0,0.9);
  392 + width: 578rpx;
  393 + }
421 394
422   - &.status_PASS {
423   - background: #2BA471;
424   - }
  395 + .status-box {
  396 + position: absolute;
  397 + top: -32rpx;
  398 + right: -12rpx;
  399 +
  400 + .status {
  401 + display: block;
  402 + height: 48rpx;
  403 + line-height: 48rpx;
  404 + font-weight: 600;
  405 + color: #fff;
  406 + font-size: 24rpx;
  407 + padding: 0 14rpx;
  408 + border-radius: 6rpx;
  409 + margin-bottom: 8rpx;
  410 +
  411 + &.status_AUDIT {
  412 + background: $theme-primary;
  413 + }
  414 +
  415 + &.status_PASS {
  416 + background: #2BA471;
  417 + }
425 418
426   - &.status_REFUSE {
427   - background: #D54941;
  419 + &.status_REFUSE {
  420 + background: #D54941;
  421 + }
  422 +
  423 + &.status_CANCEL {
  424 + background: #E7E7E7;
  425 + color: rgba(0,0,0,0.9);
  426 + }
428 427 }
429 428
430   - &.status_CANCEL {
  429 + .status2 {
  430 + display: block;
  431 + font-weight: 600;
  432 + line-height: 48rpx;
  433 + height: 48rpx;
  434 + color: #fff;
  435 + font-size: 24rpx;
  436 + padding: 0 14rpx;
  437 + border-radius: 6rpx;
431 438 background: #E7E7E7;
432   - color: rgba(0, 0, 0, 0.9);
433   - }
434   - }
  439 + color: rgba(0,0,0,0.9);
435 440
436   - .status2 {
437   - display: block;
438   - font-weight: 600;
439   - line-height: 48rpx;
440   - height: 48rpx;
441   - color: #fff;
442   - font-size: 24rpx;
443   - padding: 0 14rpx;
444   - border-radius: 6rpx;
445   - background: #E7E7E7;
446   - color: rgba(0, 0, 0, 0.9);
  441 + }
447 442
448 443 }
449 444
450 445 }
451 446
452   - }
453   -
454   - .info-row {
455   - display: flex;
456   - align-items: center;
457   - color: rgba(0, 0, 0, 0.6);
458   - font-size: 28rpx;
459   - margin-bottom: 24rpx;
460   -
461   - &:last-child {
462   - margin-bottom: 0;
463   - }
464   -
465   - text {
466   - width: 60%;
467   - line-height: 32rpx;
  447 + .info-row {
  448 + display: flex;
  449 + align-items: center;
  450 + color: rgba(0, 0, 0, 0.6);
  451 + font-size: 28rpx;
  452 + margin-bottom: 24rpx;
468 453
469 454 &:last-child {
470   - color: rgba(0, 0, 0, 0.9);
471   - width: 40%;
  455 + margin-bottom: 0;
472 456 }
473 457
474   - &.category {
475   - display: inline-block;
476   - padding: 4rpx 12rpx;
477   - border-radius: 6rpx;
478   - font-size: 24rpx;
479   - width: auto;
  458 + text {
  459 + width: 60%;
  460 + line-height: 32rpx;
480 461
481   - &.category_A {
482   - background: #FFF0ED;
483   - color: #D54941;
484   - }
485   -
486   - &.category_B {
487   - background: #FFF1E9;
488   - color: #E37318;
489   - }
490   -
491   - &.category_C {
492   - background: #F2F3FF;
493   - color: $theme-primary;
  462 + &:last-child {
  463 + color: rgba(0, 0, 0, 0.9);
  464 + width: 40%;
494 465 }
495 466
496   - &.category_D {
497   - background: #E3F9E9;
498   - color: #2BA471;
  467 + &.category {
  468 + display: inline-block;
  469 + padding: 4rpx 12rpx;
  470 + border-radius: 6rpx;
  471 + font-size: 24rpx;
  472 + width: auto;
  473 + &.category_A {
  474 + background: #FFF0ED;
  475 + color: #D54941;
  476 + }
  477 + &.category_B {
  478 + background: #FFF1E9;
  479 + color: #E37318;
  480 + }
  481 + &.category_C {
  482 + background: #F2F3FF;
  483 + color: $theme-primary;
  484 + }
  485 + &.category_D {
  486 + background: #E3F9E9;
  487 + color: #2BA471;
  488 + }
499 489 }
500 490 }
501   - }
502   -
503   - }
504   -}
505   -
506   -.filter-form {
507   - .form-item {
508   - margin-bottom: 24rpx;
509   - }
510 491
511   - .label {
512   - margin-bottom: 20rpx;
513   - color: rgba(0, 0, 0, 0.9);
514   - height: 44rpx;
515   - line-height: 44rpx;
516   - font-size: 30rpx;
  492 + }
517 493 }
518 494
519   - .fake-select {
520   - height: 80rpx;
521   - line-height: 80rpx;
522   - padding: 0 20rpx;
523   - background: #f3f3f3;
524   - border-radius: 12rpx;
525   -
526   - .placeholder {
527   - color: #999;
  495 + .filter-form {
  496 + .form-item {
  497 + margin-bottom: 24rpx;
528 498 }
529 499
530   - .value {
531   - color: #333;
  500 + .label {
  501 + margin-bottom: 20rpx;
  502 + color: rgba(0, 0, 0, 0.9);
  503 + height: 44rpx;
  504 + line-height: 44rpx;
  505 + font-size: 30rpx;
532 506 }
533   - }
534   -}
535   -
536   -/* 深度覆盖 uni-data-checkbox(mode=tag)内部的 tag 展示与间距 */
537   -::v-deep .filter-form .uni-data-checklist .checklist-group {
538   - .checklist-box {
539   - &.is--tag {
540   - width: 212rpx;
541   - margin-top: 0;
542   - margin-bottom: 24rpx;
543   - margin-right: 24rpx;
  507 +
  508 + .fake-select {
544 509 height: 80rpx;
545   - padding: 0;
  510 + line-height: 80rpx;
  511 + padding: 0 20rpx;
  512 + background: #f3f3f3;
546 513 border-radius: 12rpx;
547   - background-color: #f3f3f3;
548   - border-color: #f3f3f3;
549 514
550   - &:nth-child(3n) {
551   - margin-right: 0;
  515 + .placeholder {
  516 + color: #999;
552 517 }
553 518
554   - .checklist-content {
555   - display: flex;
556   - justify-content: center;
  519 + .value {
  520 + color: #333;
557 521 }
  522 + }
  523 + }
  524 +
  525 + /* 深度覆盖 uni-data-checkbox(mode=tag)内部的 tag 展示与间距 */
  526 + ::v-deep .filter-form .uni-data-checklist .checklist-group {
  527 + .checklist-box {
  528 + &.is--tag {
  529 + width: 212rpx;
  530 + margin-top: 0;
  531 + margin-bottom: 24rpx;
  532 + margin-right: 24rpx;
  533 + height: 80rpx;
  534 + padding: 0;
  535 + border-radius: 12rpx;
  536 + background-color: #f3f3f3;
  537 + border-color: #f3f3f3;
  538 +
  539 + &:nth-child(3n) {
  540 + margin-right: 0;
  541 + }
  542 +
  543 + .checklist-content {
  544 + display: flex;
  545 + justify-content: center;
  546 + }
558 547
559   - .checklist-text {
560   - color: rgba(0, 0, 0, 0.9);
561   - font-size: 28rpx;
  548 + .checklist-text {
  549 + color: rgba(0, 0, 0, 0.9);
  550 + font-size: 28rpx;
  551 + }
562 552 }
563   - }
564 553
565   - &.is-checked {
566   - background-color: $theme-primary-plain-bg !important;
567   - border-color: $theme-primary-plain-bg !important;
  554 + &.is-checked {
  555 + background-color: $theme-primary-plain-bg !important;
  556 + border-color: $theme-primary-plain-bg !important;
568 557
569   - .checklist-text {
570   - color: $theme-primary !important;
  558 + .checklist-text {
  559 + color: $theme-primary !important;
  560 + }
571 561 }
572 562 }
  563 +
573 564 }
574 565
575   -}
576   -</style>
\ No newline at end of file
  566 +</style>
... ...
... ... @@ -8,7 +8,7 @@
8 8 </template>
9 9 <template v-slot:footer>
10 10 <view class="serial-number-row">
11   - <uni-easyinput v-model="form.serialNumber" placeholder="自动生成编号" :inputBorder="false" disabled />
  11 + <text class="readonly-text">{{ form.serialNumber }}</text>
12 12 </view>
13 13 </template>
14 14 </uni-list-item>
... ...
... ... @@ -8,7 +8,7 @@
8 8 </template>
9 9 <template v-slot:footer>
10 10 <view class="serial-number-row">
11   - <uni-easyinput v-model="form.code" placeholder="自动生成编号" :inputBorder="false" disabled />
  11 + <text class="readonly-text value-code">{{ form.code }}</text>
12 12 <button class="generate-btn" @click="loadCode">点此生成</button>
13 13 </view>
14 14 </template>
... ... @@ -328,4 +328,19 @@ export default {
328 328 }
329 329 }
330 330 }
  331 +
  332 +
  333 +/* 只读文本样式 */
  334 +.readonly-text {
  335 + color: rgba(0, 0, 0, 0.9);
  336 + font-size: 32rpx;
  337 + line-height: 48rpx;
  338 + text-align: right;
  339 + white-space: pre-wrap;
  340 + word-break: break-all;
  341 +}
  342 +.value-code {
  343 + width: 260rpx;
  344 + text-align: left;
  345 +}
331 346 </style>
... ...
... ... @@ -175,7 +175,7 @@
175 175 if ((payload.available === '' || payload.available == null) && this.filterForm.available !== '') {
176 176 q.available = this.filterForm.available
177 177 }
178   -
  178 +
179 179 this.query = q
180 180 },
181 181 onStatusChange(e) {
... ... @@ -292,7 +292,7 @@
292 292
293 293 .list-box {
294 294 flex: 1;
295   - padding-top: 132rpx;
  295 + padding-top: 140rpx;
296 296
297 297 &.pad-batch {
298 298 padding-bottom: 144rpx;
... ... @@ -317,7 +317,7 @@
317 317 .status-box {
318 318 position: absolute;
319 319 top: -32rpx;
320   - right: -32rpx;
  320 + right: -12rpx;
321 321
322 322 .status {
323 323 display: block;
... ... @@ -485,4 +485,4 @@
485 485
486 486 }
487 487
488   -</style>
\ No newline at end of file
  488 +</style>
... ...
... ... @@ -8,7 +8,7 @@
8 8 </template>
9 9 <template v-slot:footer>
10 10 <view class="serial-number-row">
11   - <uni-easyinput v-model="form.code" placeholder="自动生成编号" :inputBorder="false" disabled />
  11 + <text class="readonly-text">{{ form.code }}</text>
12 12 </view>
13 13 </template>
14 14 </uni-list-item>
... ... @@ -336,4 +336,12 @@ export default {
336 336 }
337 337 }
338 338 }
  339 +.readonly-text {
  340 + color: rgba(0, 0, 0, 0.9);
  341 + font-size: 32rpx;
  342 + line-height: 48rpx;
  343 + text-align: right;
  344 + white-space: pre-wrap;
  345 + word-break: break-all;
  346 +}
339 347 </style>
... ...
  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">{{ form.deptName }}</text>
  7 + <view :class="['status', `status_${form.status}`]" />
  8 + <view class="row"><text class="label">要车日期</text><text class="value">{{ form.applyDate }}</text></view>
  9 + </view>
  10 +
  11 + <!-- 产品 -->
  12 + <view class="section2">
  13 + <Product mode="view" :list="form.delayedShipmentDetailList"
  14 + />
  15 + </view>
  16 + </view>
  17 + </scroll-view>
  18 + <detail-buttons :buttons="displayButtons" @click="handleButtonClick" />
  19 + </view>
  20 +</template>
  21 +
  22 +<script>
  23 +import { getDetailApi, cancelApi } from '@/api/delay_invoice.js'
  24 +import Product from './product.vue'
  25 +import DetailButtons from '@/components/detail-buttons/index.vue'
  26 +
  27 +export default {
  28 + name: 'DelayInvoiceDetail',
  29 + components: { Product, DetailButtons },
  30 + data() {
  31 + return {
  32 + form: {},
  33 + buttons: [
  34 + { text: '编辑', visible: true, variant: 'outline', event: 'edit' },
  35 + { text: '审核详情', visible: true, variant: 'outline', event: 'auditDetail' },
  36 + { text: '审核', visible: true, variant: 'primary', event: 'audit' },
  37 + { text: '取消', visible: true, variant: 'outline', event: 'cancel', style: { color: 'rgba(0,0,0,0.9)', border: '1px solid #DCDCDC' } },
  38 + ]
  39 + }
  40 + },
  41 + computed: {
  42 + statusFlags() {
  43 + const m = this.form || {}
  44 + const e = String(m.status || '')
  45 + return {
  46 + isRefuse: e === 'REFUSE' || false,
  47 + isAudit: e === 'AUDIT' || false,
  48 + canEdit: e === 'REFUSE' && m.delayedCreateBy || false,
  49 + canAudit: e === 'AUDIT' && m.showExamine || false,
  50 + canCancel: e === 'REFUSE' && m.delayedCreateBy || false,
  51 + }
  52 + },
  53 + displayButtons() {
  54 + const f = this.statusFlags
  55 + return [
  56 + { ...this.buttons[0], visible: f.canEdit && this.$auth.hasPermi('shipping-plan-manage:delay-invoice:modify') },
  57 + { ...this.buttons[1], visible: this.$auth.hasPermi('shipping-plan-manage:delay-invoice:review') },
  58 + { ...this.buttons[2], visible: f.canAudit && this.$auth.hasPermi('shipping-plan-manage:delay-invoice:approve') },
  59 + { ...this.buttons[3], visible: f.canCancel && this.$auth.hasPermi('shipping-plan-manage:delay-invoice:cancel') },
  60 + ]
  61 + }
  62 + },
  63 + onLoad(query) {
  64 + const id = (query && (query.id || query.code)) || ''
  65 + if (id) this.loadDetail(id)
  66 + },
  67 + methods: {
  68 + async loadDetail(id) {
  69 + try {
  70 + const res = await getDetailApi(id)
  71 + this.form = res.data || {}
  72 + } catch (e) {
  73 + this.form = {}
  74 + }
  75 + },
  76 + handleButtonClick(btn) {
  77 + if (!btn || btn.disabled) return
  78 + const map = {
  79 + edit: () => this.onEdit(),
  80 + auditDetail: () => this.onAuditDetail(),
  81 + audit: () => this.onAudit(),
  82 + fill: () => this.onFill(),
  83 + cancel: () => this.onCancel(),
  84 + }
  85 + const fn = map[btn.event]
  86 + if (typeof fn === 'function') fn()
  87 + },
  88 + onEdit() {
  89 + const id = this.form.id || this.form.code
  90 + if (id) uni.navigateTo({ url: `/pages/delay_invoice/modify?id=${id}` })
  91 + },
  92 + onAuditDetail() {
  93 + uni.setStorageSync('sourceBusinessId', this.form.id)
  94 + uni.navigateTo({ url: '/pages/flow/audit_detail' })
  95 + },
  96 + onAudit() {
  97 + uni.setStorageSync('sourceBusinessId', this.form.id)
  98 + uni.navigateTo({ url: '/pages/flow/audit' })
  99 + },
  100 + onCancel() {
  101 + const id = this.form.id || this.form.code
  102 + if (!id) return
  103 + uni.showModal({
  104 + title: '提示',
  105 + content: '确定要取消该延期发货单吗?',
  106 + success: async (res) => {
  107 + if (res.confirm) {
  108 + try {
  109 + await cancelApi(id)
  110 + uni.showToast({ title: '取消成功', icon: 'success' })
  111 + setTimeout(() => { uni.redirectTo({ url: '/pages/delay_invoice/index' }) }, 300)
  112 + } catch (e) {
  113 + uni.showToast({ title: (e && e.msg) || '取消失败', icon: 'none' })
  114 + }
  115 + }
  116 + }
  117 + })
  118 + },
  119 + }
  120 +}
  121 +</script>
  122 +
  123 +<style lang="scss" scoped>
  124 +.page {
  125 + display: flex;
  126 + flex-direction: column;
  127 + height: 100vh;
  128 +}
  129 +
  130 +.scroll {
  131 + flex: 1;
  132 + background: #f3f3f3;
  133 +}
  134 +
  135 +.detail-page {
  136 + padding-bottom: 150rpx;
  137 +}
  138 +
  139 +.section {
  140 + padding: 32rpx;
  141 + background: #fff;
  142 + margin-bottom: 20rpx;
  143 + position: relative;
  144 +
  145 + .status {
  146 + position: absolute;
  147 + top: 16rpx;
  148 + right: 52rpx;
  149 + width: 180rpx;
  150 + height: 146rpx;
  151 + background-repeat: no-repeat;
  152 + background-size: 100% 100%;
  153 + background-position: center;
  154 +
  155 + &_AUDIT {
  156 + background-image: url('~@/static/images/dev_manage/status_1.png');
  157 + }
  158 +
  159 + &_PASS {
  160 + background-image: url('~@/static/images/dev_manage/status_2.png');
  161 + }
  162 +
  163 + &_REFUSE {
  164 + background-image: url('~@/static/images/dev_manage/status_3.png');
  165 + }
  166 +
  167 + &_CANCEL {
  168 + background-image: url('~@/static/images/dev_manage/status_4.png');
  169 + }
  170 +
  171 + }
  172 +}
  173 +
  174 +.row {
  175 + display: flex;
  176 + margin-bottom: 28rpx;
  177 +
  178 + &:last-child {
  179 + margin-bottom: 0;
  180 + }
  181 +
  182 + &.company {
  183 + font-size: 36rpx;
  184 + font-weight: 600;
  185 + color: rgba(0, 0, 0, 0.9);
  186 + padding-top: 10rpx;
  187 + margin-bottom: 32rpx;
  188 + line-height: 50rpx;
  189 + }
  190 +
  191 + .label {
  192 + width: 240rpx;
  193 + line-height: 32rpx;
  194 + font-size: 28rpx;
  195 + color: rgba(0, 0, 0, 0.6);
  196 + }
  197 +
  198 + .value {
  199 + flex: 1;
  200 + line-height: 32rpx;
  201 + font-size: 28rpx;
  202 + color: rgba(0, 0, 0, 0.9);
  203 + text-align: right;
  204 + word-break: break-all;
  205 + }
  206 +}
  207 +
  208 +.title-header {
  209 + background-color: #fff;
  210 + display: flex;
  211 + align-items: center;
  212 + padding: 32rpx 32rpx 22rpx;
  213 + border-bottom: 1rpx dashed #f0f0f0;
  214 +
  215 + &_icon {
  216 + width: 32rpx;
  217 + height: 28rpx;
  218 + margin-right: 16rpx;
  219 + }
  220 +
  221 + span {
  222 + color: rgba(0, 0, 0, 0.9);
  223 + font-size: 32rpx;
  224 + line-height: 44rpx;
  225 + font-weight: 600;
  226 + }
  227 +}
  228 +</style>
... ...
  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 +
  15 + <!-- 列表卡片组件 -->
  16 + <view class="list-box">
  17 + <card-list ref="cardRef" :fetch-fn="fetchList" :query="query" :extra="extraParams" row-key="id"
  18 + :enable-refresh="true" :enable-load-more="true" @loaded="onCardLoaded" @error="onCardError">
  19 + <template v-slot="{ item, selected }">
  20 + <view class="card" @click.stop="onCardClick(item)">
  21 + <view class="card-header">
  22 + <text class="title omit2">{{ item.deptName }}</text>
  23 + <text :class="['status', `status_${item.status}`]">{{ filterStatus(item.status) }}</text>
  24 + </view>
  25 + <view class="info-row">
  26 + <text>申请日期</text><text>{{ item.applyDate || '-' }}</text>
  27 + </view>
  28 + </view>
  29 + </template>
  30 + </card-list>
  31 + </view>
  32 +
  33 +
  34 +
  35 + <!-- 筛选弹框 -->
  36 + <filter-modal :visible.sync="filterVisible" :value.sync="filterForm" title="筛选" @reset="onFilterReset"
  37 + @confirm="onFilterConfirm">
  38 + <template v-slot="{ model }">
  39 + <view class="filter-form">
  40 + <view class="form-item">
  41 + <view class="label">状态</view>
  42 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  43 + v-model="model.status" @change="onStatusChange" :localdata="statusLocal" />
  44 + </view>
  45 + <view class="form-item">
  46 + <view class="label">申请日期</view>
  47 + <uni-datetime-picker type="daterange" v-model="model.dateRange" start="2023-01-01"
  48 + @change="onDateChange($event, model)" />
  49 + </view>
  50 + </view>
  51 + </template>
  52 + </filter-modal>
  53 + </view>
  54 +</template>
  55 +
  56 +<script>
  57 +import CardList from '@/components/card/index.vue'
  58 +import FilterModal from '@/components/filter/index.vue'
  59 +import SingleSelectSheet from '@/components/single-select/index.vue'
  60 +import {
  61 + queryApi
  62 +} from '@/api/delay_invoice.js'
  63 +import {
  64 + getDicByCodes
  65 +} from '@/utils/dic'
  66 +
  67 +export default {
  68 + components: {
  69 + CardList,
  70 + FilterModal,
  71 + SingleSelectSheet
  72 + },
  73 + data() {
  74 + return {
  75 + searchKeyword: '',
  76 + searchKeywordDebounced: '',
  77 + tabs: [],
  78 + // 给到 card 的筛选值
  79 + query: {
  80 + status: '',
  81 + dateRange: []
  82 + },
  83 + extraParams: {},
  84 +
  85 + // 批量选择
  86 + rowKey: 'id',
  87 + currentItems: [],
  88 +
  89 + // 筛选弹框
  90 + filterVisible: false,
  91 + filterForm: {
  92 + status: '',
  93 + dateRange: []
  94 + },
  95 + dicOptions: {
  96 + AUDIT_STATUS: [],
  97 + },
  98 + statusLocal: [],
  99 + }
  100 + },
  101 + computed: {
  102 + extraCombined() {
  103 + return {
  104 + deptName: this.searchKeywordDebounced || undefined
  105 + }
  106 + }
  107 + },
  108 + watch: {
  109 + extraCombined: {
  110 + deep: true,
  111 + handler(v) {
  112 + this.extraParams = v
  113 + },
  114 + immediate: true
  115 + },
  116 +
  117 + },
  118 + created() {
  119 + this.loadAllDicData()
  120 + },
  121 + onLoad() { },
  122 + // 页面触底兜底:当页面自身滚动到底部时,转调卡片组件加载更多
  123 + onReachBottom() {
  124 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) {
  125 + this.$refs.cardRef.onLoadMore()
  126 + }
  127 + },
  128 + beforeDestroy() {
  129 + if (this.searchDebounceTimer) {
  130 + clearTimeout(this.searchDebounceTimer)
  131 + this.searchDebounceTimer = null
  132 + }
  133 + },
  134 + methods: {
  135 + onCardLoaded({
  136 + items
  137 + }) {
  138 + this.currentItems = items
  139 + },
  140 + onCardError() {
  141 + uni.showToast({
  142 + title: '列表加载失败',
  143 + icon: 'none'
  144 + })
  145 + },
  146 + // 输入实时搜索:1200ms 防抖,仅在停止输入超过阈值后刷新
  147 + onSearchInput(val) {
  148 + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer)
  149 + this.searchDebounceTimer = setTimeout(() => {
  150 + this.searchKeywordDebounced = this.searchKeyword
  151 + this.searchDebounceTimer = null
  152 + }, 1200)
  153 + },
  154 + // uni-search-bar 确认搜索:更新关键字并触发 CardList 刷新
  155 + search(e) {
  156 + const val = e && e.value != null ? e.value : this.searchKeyword
  157 + this.searchKeyword = val
  158 + this.searchKeywordDebounced = val
  159 + },
  160 + onAdd() {
  161 + uni.navigateTo({
  162 + url: '/pages/replenishment_order/add'
  163 + })
  164 + },
  165 + openFilter() {
  166 + this.filterVisible = true
  167 + },
  168 + onFilterReset(payload) {
  169 + this.filterForm = payload
  170 + },
  171 + onFilterConfirm(payload) {
  172 + if ((payload.status === '' || payload.status == null) && this.filterForm.status !== '') {
  173 + payload.status = this.filterForm.status
  174 + }
  175 + this.query = {
  176 + ...payload
  177 + }
  178 + },
  179 + onStatusChange(e) {
  180 + const raw = e && e.detail && e.detail.value !== undefined ?
  181 + e.detail.value :
  182 + (e && e.value !== undefined ? e.value : '')
  183 + this.filterForm.status = raw
  184 + },
  185 +
  186 + onDateChange(e, model) {
  187 + // 确保同步更新 filterForm,避免数据不同步
  188 + this.filterForm.dateRange = e
  189 + },
  190 +
  191 + // 列表接口(真实请求)
  192 + fetchList({
  193 + pageIndex,
  194 + pageSize,
  195 + query,
  196 + extra
  197 + }) {
  198 + const params = {
  199 + pageIndex,
  200 + pageSize,
  201 + ...extra,
  202 + ...query
  203 + }
  204 + if (Array.isArray(params.dateRange) && params.dateRange.length === 2) {
  205 + params.applyDateStart = params.dateRange[0]
  206 + params.applyDateEnd = params.dateRange[1]
  207 + delete params.dateRange
  208 + }
  209 + if (this.searchKeywordDebounced) {
  210 + params.deptName = this.searchKeywordDebounced
  211 + }
  212 + return queryApi(params)
  213 + .then(res => {
  214 + const _data = res.data || {};
  215 + const records = _data.datas || [];
  216 + const totalCount = _data.totalCount || 0;
  217 + const hasNext = _data.hasNext || false
  218 + return {
  219 + records,
  220 + totalCount,
  221 + hasNext
  222 + }
  223 + })
  224 + .catch(err => {
  225 + console.error('fetchList error', err)
  226 + this.onCardError()
  227 + return {
  228 + records: [],
  229 + totalCount: 0,
  230 + hasNext: false
  231 + }
  232 + })
  233 + },
  234 + loadAllDicData() {
  235 + const dicCodes = ['AUDIT_STATUS']
  236 + return getDicByCodes(dicCodes).then(results => {
  237 + this.dicOptions.AUDIT_STATUS = results.AUDIT_STATUS.data || []
  238 + this.statusLocal = (this.dicOptions.AUDIT_STATUS || []).map(it => ({
  239 + value: it.code,
  240 + text: it.name
  241 + }))
  242 + }).catch(() => {
  243 + this.dicOptions = {
  244 + AUDIT_STATUS: [],
  245 + }
  246 + this.statusLocal = []
  247 + })
  248 + },
  249 + onCardClick(item) {
  250 + const id = (item && (item.id || item.code)) || ''
  251 + if (!id) return
  252 + const query = '?id=' + encodeURIComponent(id)
  253 + uni.navigateTo({
  254 + url: '/pages/delay_invoice/detail' + query
  255 + })
  256 + },
  257 + filterStatus(status) {
  258 + return this.statusLocal.filter(item => item.value === status)[0].text || '';
  259 + },
  260 + }
  261 +}
  262 +</script>
  263 +
  264 +<style lang="scss" scoped>
  265 +.page {
  266 + display: flex;
  267 + flex-direction: column;
  268 + height: 100vh;
  269 +}
  270 +
  271 +.dev-list-fixed {
  272 + position: fixed;
  273 + top: 96rpx;
  274 + left: 0;
  275 + right: 0;
  276 + z-index: 2;
  277 + background: #fff;
  278 +
  279 + .search-row {
  280 + display: flex;
  281 + align-items: center;
  282 + padding: 16rpx 32rpx;
  283 +
  284 + .uni-searchbar {
  285 + padding: 0;
  286 + flex: 1;
  287 + }
  288 +
  289 + .tool-icons {
  290 + display: flex;
  291 +
  292 + .tool-icon {
  293 + width: 48rpx;
  294 + height: 48rpx;
  295 + display: block;
  296 + margin-left: 32rpx;
  297 + }
  298 + }
  299 + }
  300 +
  301 +}
  302 +
  303 +/* 仅当前页覆盖 uni-search-bar 盒子高度 */
  304 +::v-deep .uni-searchbar__box {
  305 + height: 80rpx !important;
  306 + justify-content: start;
  307 +
  308 + .uni-searchbar__box-search-input {
  309 + font-size: 32rpx !important;
  310 + }
  311 +}
  312 +
  313 +.list-box {
  314 + flex: 1;
  315 + padding-top: 140rpx;
  316 +
  317 + &.pad-batch {
  318 + padding-bottom: 144rpx;
  319 + }
  320 +
  321 + .card {
  322 + position: relative;
  323 + }
  324 +
  325 + .card-header {
  326 + margin-bottom: 28rpx;
  327 + position: relative;
  328 +
  329 + .title {
  330 + font-size: 36rpx;
  331 + font-weight: 600;
  332 + line-height: 50rpx;
  333 + color: rgba(0, 0, 0, 0.9);
  334 + width: 578rpx;
  335 + }
  336 +
  337 + .status {
  338 + font-weight: 600;
  339 + position: absolute;
  340 + top: -32rpx;
  341 + right: -12rpx;
  342 + height: 48rpx;
  343 + line-height: 48rpx;
  344 + color: #fff;
  345 + font-size: 24rpx;
  346 + padding: 0 14rpx;
  347 + border-radius: 6rpx;
  348 +
  349 + // 审核中
  350 + &.status_AUDIT {
  351 + background: $theme-primary;
  352 + }
  353 +
  354 + // 审核通过
  355 + &.status_PASS {
  356 + background: #2BA471;
  357 + }
  358 +
  359 + // 已驳回
  360 + &.status_REFUSE {
  361 + background: #d54941;
  362 + }
  363 +
  364 + // 已取消
  365 + &.status_CANCEL {
  366 + background: #e7e7e7;
  367 + color: rgba(0, 0, 0, 0.6);
  368 + }
  369 +
  370 + }
  371 +
  372 + }
  373 +
  374 + .info-row {
  375 + display: flex;
  376 + align-items: center;
  377 + color: rgba(0, 0, 0, 0.6);
  378 + font-size: 28rpx;
  379 + margin-bottom: 24rpx;
  380 +
  381 + &:last-child {
  382 + margin-bottom: 0;
  383 + }
  384 +
  385 + text {
  386 + width: 60%;
  387 + line-height: 32rpx;
  388 +
  389 + &:last-child {
  390 + color: rgba(0, 0, 0, 0.9);
  391 + width: 40%;
  392 + }
  393 +
  394 + &.category {
  395 + display: inline-block;
  396 + padding: 4rpx 12rpx;
  397 + border-radius: 6rpx;
  398 + font-size: 24rpx;
  399 + width: auto;
  400 +
  401 + &.category_A {
  402 + background: #FFF0ED;
  403 + color: #D54941;
  404 + }
  405 +
  406 + &.category_B {
  407 + background: #FFF1E9;
  408 + color: #E37318;
  409 + }
  410 +
  411 + &.category_C {
  412 + background: #F2F3FF;
  413 + color: $theme-primary;
  414 + }
  415 +
  416 + &.category_D {
  417 + background: #E3F9E9;
  418 + color: #2BA471;
  419 + }
  420 + }
  421 + }
  422 +
  423 + }
  424 +}
  425 +
  426 +.filter-form {
  427 + .form-item {
  428 + margin-bottom: 24rpx;
  429 + }
  430 +
  431 + .label {
  432 + margin-bottom: 20rpx;
  433 + color: rgba(0, 0, 0, 0.9);
  434 + height: 44rpx;
  435 + line-height: 44rpx;
  436 + font-size: 30rpx;
  437 + }
  438 +
  439 + .uni-easyinput {
  440 + border: 1rpx solid #f3f3f3;
  441 + }
  442 +
  443 +}
  444 +
  445 +/* 深度覆盖 uni-data-checkbox(mode=tag)内部的 tag 展示与间距 */
  446 +::v-deep .filter-form .uni-data-checklist .checklist-group {
  447 + .checklist-box {
  448 + &.is--tag {
  449 + width: 212rpx;
  450 + margin-top: 0;
  451 + margin-bottom: 24rpx;
  452 + margin-right: 24rpx;
  453 + height: 80rpx;
  454 + padding: 0;
  455 + border-radius: 12rpx;
  456 + background-color: #f3f3f3;
  457 + border-color: #f3f3f3;
  458 +
  459 + &:nth-child(3n) {
  460 + margin-right: 0;
  461 + }
  462 +
  463 + .checklist-content {
  464 + display: flex;
  465 + justify-content: center;
  466 + }
  467 +
  468 + .checklist-text {
  469 + color: rgba(0, 0, 0, 0.9);
  470 + font-size: 28rpx;
  471 + }
  472 + }
  473 +
  474 + &.is-checked {
  475 + background-color: $theme-primary-plain-bg !important;
  476 + border-color: $theme-primary-plain-bg !important;
  477 +
  478 + .checklist-text {
  479 + color: $theme-primary !important;
  480 + }
  481 + }
  482 + }
  483 +
  484 +}
  485 +</style>
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <uni-list>
  5 + <view class="section">
  6 + <uni-list-item title="要车日期">
  7 + <template v-slot:footer>
  8 + <view class="readonly-text">{{ form.applyDate }}</view>
  9 + </template>
  10 + </uni-list-item>
  11 + <uni-list-item title="所属办">
  12 + <template v-slot:footer>
  13 + <view class="readonly-text">{{ form.deptName }}</view>
  14 + </template>
  15 + </uni-list-item>
  16 + </view>
  17 +
  18 + <!-- 产品 -->
  19 + <view class="section2">
  20 + <!-- mode="add" 允许编辑 -->
  21 + <Product mode="add" :list="initDelayedShipmentDetailList" @change="delayedShipmentDetailListChange"
  22 + :orderDate="form.orderDate" />
  23 + </view>
  24 + <view class="footer">
  25 + <button class="btn submit" type="primary" @click="onSubmit">保存</button>
  26 + </view>
  27 + </uni-list>
  28 + </scroll-view>
  29 + </view>
  30 +</template>
  31 +
  32 +<script>
  33 +import { updateApi, getDetailApi } from '@/api/delay_invoice.js'
  34 +import Product from './product.vue'
  35 +
  36 +export default {
  37 + name: 'DelayInvoiceModify',
  38 + components: { Product },
  39 + data() {
  40 + return {
  41 + form: {
  42 + id: '',
  43 + },
  44 + initDelayedShipmentDetailList: [],
  45 + }
  46 + },
  47 + onLoad(query) {
  48 + const id = (query && (query.id || query.code)) || ''
  49 + if (id) {
  50 + this.loadDetail(id)
  51 + }
  52 + },
  53 + methods: {
  54 + async loadDetail(id) {
  55 + try {
  56 + const res = await getDetailApi(id)
  57 + const m = res.data || {}
  58 + const next = { ...this.form, ...m }
  59 + // 确保ID存在
  60 + next.id = m.id || id
  61 + // 映射列表
  62 + // 注意:详情返回的是 replenishmentOrderLineList,需要赋值给 initDelayedShipmentDetailList 以便 Product 组件初始化
  63 + // 且需要处理字段兼容性,确保 Product 组件能正确显示和编辑
  64 + const lines = Array.isArray(m.delayedShipmentDetailList) ? m.delayedShipmentDetailList.map(x => ({
  65 + ...x,
  66 + // 确保 Product 组件需要的字段存在
  67 + // Product组件使用: quantity(需发), shippedQuantity(实发), supplementaryQuantity(需求补货), salesPrice(单价)
  68 + // 详情接口返回的字段应该已经包含了这些,如果有差异需要在此处转换
  69 + // 注意:add.vue中 onRelateConfirm 做了映射,这里是回显,通常直接使用即可
  70 + })) : []
  71 +
  72 + this.form = next;
  73 + this.initDelayedShipmentDetailList = lines;
  74 + } catch (e) {
  75 + uni.showToast({ title: '加载失败', icon: 'none' })
  76 + }
  77 + },
  78 + validateLineListRequired() {
  79 + const list = Array.isArray(this.form.delayedShipmentDetailList) ? this.form.delayedShipmentDetailList : []
  80 + if (list.length === 0) {
  81 + uni.showToast({ title: '请先添加产品', icon: 'none' })
  82 + return false
  83 + }
  84 + const fields = [
  85 + { key: 'applyShipmentDate', label: '现申请发货日期' },
  86 + ]
  87 + for (let i = 0; i < list.length; i++) {
  88 + const it = list[i] || {}
  89 + for (const f of fields) {
  90 + const v = it && it[f.key]
  91 + if (v === undefined || v === null || String(v).trim() === '') {
  92 + uni.showToast({ title: `产品第${i + 1}条:${f.label}不能为空!`, icon: 'none' })
  93 + return false
  94 + }
  95 + }
  96 + }
  97 + return true
  98 + },
  99 + async onSubmit() {
  100 + if (!this.validateLineListRequired()) return
  101 + const payload = { ...this.form }
  102 +
  103 + console.log('onSubmit__payload', payload)
  104 + try {
  105 + await updateApi(payload)
  106 + uni.showToast({ title: '保存成功', icon: 'success' })
  107 + setTimeout(() => { uni.redirectTo({ url: '/pages/delay_invoice/index' }) }, 300)
  108 + } catch (e) {
  109 + uni.showToast({ title: (e && e.msg) || '保存失败', icon: 'none' })
  110 + }
  111 + },
  112 + delayedShipmentDetailListChange(data) {
  113 + const list = Array.isArray(data) ? data : []
  114 + this.form.delayedShipmentDetailList = list
  115 + },
  116 + }
  117 +}
  118 +</script>
  119 +
  120 +<style lang="scss" scoped>
  121 +.page {
  122 + display: flex;
  123 + flex-direction: column;
  124 + height: 100%;
  125 +}
  126 +
  127 +.scroll {
  128 + flex: 1;
  129 + padding: 6rpx 0 400rpx;
  130 +}
  131 +
  132 +
  133 +
  134 +.title-header {
  135 + background-color: #fff;
  136 + display: flex;
  137 + align-items: center;
  138 + padding: 32rpx 32rpx 22rpx;
  139 +
  140 + .title-header_icon {
  141 + width: 32rpx;
  142 + height: 28rpx;
  143 + margin-right: 16rpx;
  144 + }
  145 +
  146 + span {
  147 + color: rgba(0, 0, 0, 0.9);
  148 + font-size: 32rpx;
  149 + line-height: 44rpx;
  150 + font-weight: 600;
  151 + }
  152 +}
  153 +
  154 +
  155 +.section {
  156 + background: #fff;
  157 + margin-bottom: 20rpx;
  158 +}
  159 +
  160 +.section2 {
  161 + background: #f1f1f1;
  162 +}
  163 +
  164 +::v-deep .uni-list {
  165 + background: transparent;
  166 +
  167 + &-item {
  168 + &__extra-text {
  169 + font-size: 32rpx;
  170 + }
  171 +
  172 + &__content-title {
  173 + font-size: 32rpx;
  174 + color: rgba(0, 0, 0, 0.9);
  175 + }
  176 +
  177 + &__container {
  178 + padding: 32rpx;
  179 + // align-items: center;
  180 +
  181 + .uni-easyinput {
  182 +
  183 + .is-disabled {
  184 + background-color: transparent !important;
  185 + }
  186 +
  187 + &__placeholder-class {
  188 + font-size: 32rpx;
  189 + color: rgba(0, 0, 0, 0.4);
  190 + }
  191 +
  192 + &__content {
  193 + border: none;
  194 +
  195 + &-input {
  196 + padding-left: 0 !important;
  197 + height: 48rpx;
  198 + line-height: 48rpx;
  199 + font-size: 32rpx;
  200 + }
  201 +
  202 + .content-clear-icon {
  203 + font-size: 44rpx !important;
  204 + }
  205 + }
  206 + }
  207 +
  208 + .amount-row {
  209 + flex: 1;
  210 + display: flex;
  211 + align-items: center;
  212 +
  213 + .uni-easyinput {
  214 + flex: 1;
  215 + }
  216 +
  217 + .unit {
  218 + margin-left: 16rpx;
  219 + color: rgba(0, 0, 0, 0.9);
  220 + }
  221 + }
  222 +
  223 + .item-title,
  224 + .uni-list-item__content {
  225 + flex: none;
  226 + min-height: 48rpx;
  227 + line-height: 48rpx;
  228 + font-size: 32rpx;
  229 + position: relative;
  230 + width: 210rpx;
  231 + margin-right: 32rpx;
  232 + color: rgba(0, 0, 0, 0.9);
  233 + padding-right: 0;
  234 +
  235 +
  236 + .required {
  237 + color: red;
  238 + position: absolute;
  239 + top: 50%;
  240 + transform: translateY(-50%);
  241 + left: -16rpx;
  242 + }
  243 + }
  244 +
  245 + }
  246 +
  247 + &.select-item {
  248 + &.is-empty {
  249 + .uni-list-item__extra-text {
  250 + color: rgba(0, 0, 0, 0.4) !important;
  251 + }
  252 + }
  253 +
  254 + &.is-filled {
  255 + .uni-list-item__extra-text {
  256 + color: rgba(0, 0, 0, 0.9) !important;
  257 + }
  258 + }
  259 +
  260 + .serial-number-row {
  261 + display: flex;
  262 + align-items: center;
  263 + }
  264 +
  265 + }
  266 +
  267 + &.mgb10 {
  268 + margin-bottom: 20rpx;
  269 + }
  270 +
  271 + }
  272 +
  273 + .title-header {
  274 + background-color: #fff;
  275 + display: flex;
  276 + align-items: center;
  277 + padding: 32rpx 32rpx 22rpx;
  278 +
  279 + &_icon {
  280 + width: 32rpx;
  281 + height: 28rpx;
  282 + margin-right: 16rpx;
  283 + }
  284 +
  285 + span {
  286 + color: rgba(0, 0, 0, 0.9);
  287 + font-size: 32rpx;
  288 + line-height: 44rpx;
  289 + font-weight: 600;
  290 + }
  291 + }
  292 +}
  293 +
  294 +/* 只读 easyinput 根据内容自适应高度 */
  295 +::v-deep .uni-list-item__container {
  296 + align-items: flex-start;
  297 +}
  298 +
  299 +/* 只读文本样式 */
  300 +.readonly-text {
  301 + color: rgba(0, 0, 0, 0.9);
  302 + font-size: 32rpx;
  303 + line-height: 48rpx;
  304 + text-align: right;
  305 + white-space: pre-wrap;
  306 + word-break: break-all;
  307 +}
  308 +
  309 +
  310 +.footer {
  311 + position: fixed;
  312 + left: 0;
  313 + right: 0;
  314 + bottom: 0;
  315 + padding: 0 32rpx 32rpx;
  316 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  317 + background: #fff;
  318 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  319 + z-index: 10;
  320 +
  321 + .btn {
  322 + height: 80rpx;
  323 + line-height: 80rpx;
  324 + border-radius: 12rpx;
  325 + font-size: 32rpx;
  326 + }
  327 +
  328 + .submit {
  329 + background: $theme-primary;
  330 + color: #fff;
  331 + }
  332 +
  333 + .view-total {
  334 + padding: 20rpx 0;
  335 +
  336 + .head {
  337 + font-size: 32rpx;
  338 + font-weight: 600;
  339 + line-height: 50rpx;
  340 + color: rgba(0, 0, 0, 0.9);
  341 + padding-bottom: 16rpx;
  342 + margin-bottom: 24rpx;
  343 + border-bottom: 1px dashed #E7E7E7;
  344 + }
  345 +
  346 + .row {
  347 + display: flex;
  348 + margin-bottom: 24rpx;
  349 + line-height: 32rpx;
  350 +
  351 + .row2 {
  352 + width: 50%;
  353 + }
  354 +
  355 + .label {
  356 + width: 180rpx;
  357 + margin-right: 14rpx;
  358 + color: rgba(0, 0, 0, 0.6);
  359 + font-size: 28rpx;
  360 + }
  361 +
  362 + .value {
  363 + flex: 1;
  364 + color: rgba(0, 0, 0, 0.9);
  365 + font-size: 28rpx;
  366 + white-space: pre-wrap;
  367 + word-break: break-all;
  368 + }
  369 + }
  370 + }
  371 +}
  372 +</style>
\ No newline at end of file
... ...
  1 +<template>
  2 + <view class="product">
  3 +
  4 + <!-- 新增&详情-产品 -->
  5 + <view class="header bp">
  6 + <image class="opCollapse" src="/static/images/title.png" />
  7 + <text class="title">{{ title || '产品' }}</text>
  8 + <view class="ops">
  9 + <!-- <image v-if="mode === 'add'" class="opAdd" @click="onAdd" src="/static/images/plus.png" /> -->
  10 + <view v-if="mode === 'view'" class="op1" @click="toggleViewCollapse">
  11 + <image class="opAdd" :src="collapsedView ? '/static/images/down.png' : '/static/images/up.png'" />
  12 + <text class="op">{{ collapsedView ? '展开' : '收起' }} </text>
  13 + </view>
  14 +
  15 + </view>
  16 + </view>
  17 +
  18 + <view v-if="mode === 'add'" class="section">
  19 + <view v-for="(item, idx) in items" :key="'a-' + idx" class="block">
  20 + <uni-list class="edit-list">
  21 + <uni-list-item title="订单编号">
  22 + <template v-slot:footer>
  23 + <view class="value">{{ item.orderNo }}</view>
  24 + </template>
  25 + </uni-list-item>
  26 + <uni-list-item title="原订单计划发货日期">
  27 + <template v-slot:footer>
  28 + <view class="value">{{ item.deliveryDate }}</view>
  29 + </template>
  30 + </uni-list-item>
  31 + <uni-list-item title="现申请发货日期">
  32 + <template v-slot:footer>
  33 + <uni-datetime-picker type="date" v-model="item.applyShipmentDate" />
  34 + </template>
  35 + </uni-list-item>
  36 +
  37 + <view v-show="!item.collapsed">
  38 + <uni-list-item title="申请次数">
  39 + <template v-slot:footer>
  40 + <view class="value">{{ item.applyCount }}</view>
  41 + </template>
  42 + </uni-list-item>
  43 + <uni-list-item title="订单类型">
  44 + <template v-slot:footer>
  45 + <view class="value">{{ item.orderType }}</view>
  46 + </template>
  47 + </uni-list-item>
  48 + <uni-list-item title="所属分厂">
  49 + <template v-slot:footer>
  50 + <view class="value">{{ item.workshopName }}</view>
  51 + </template>
  52 + </uni-list-item>
  53 + <uni-list-item title="客户名称">
  54 + <template v-slot:footer>
  55 + <view class="value">{{ item.customerName }}</view>
  56 + </template>
  57 + </uni-list-item>
  58 + <uni-list-item title="发货数量">
  59 + <template v-slot:footer>
  60 + <view class="value">{{ item.quantity }}</view>
  61 + </template>
  62 + </uni-list-item>
  63 + <uni-list-item title="延期原因">
  64 + <template v-slot:footer>
  65 + <uni-easyinput v-model="item.delayReason" placeholder="请输入延期原因" :inputBorder="false" />
  66 + </template>
  67 + </uni-list-item>
  68 + </view>
  69 + </uni-list>
  70 +
  71 + <view class="block-ops">
  72 + <!-- <div class="del" @click="onRemove(item.purchaseOrderId)">
  73 + <image src="/static/images/delete.png" class="icon" />
  74 + 删除
  75 + </div> -->
  76 + <div class="toggle" @click="toggleItem(idx)">
  77 + <image :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'"
  78 + class="icon" />
  79 + {{ item.collapsed ? '展开' : '收起' }}
  80 + </div>
  81 + </view>
  82 + </view>
  83 + </view>
  84 +
  85 + <view v-else-if="mode === 'view'" class="view-list" v-show="!collapsedView">
  86 + <view v-for="(item, idx) in items" :key="'v-' + idx" class="card">
  87 + <view class="row"><text class="label">订单编号</text><text class="value">{{ item.orderNo }}</text></view>
  88 + <view class="row"><text class="label">原订单计划发货日期</text><text class="value">{{ item.deliveryDate }}</text>
  89 + </view>
  90 + <view class="row"><text class="label">现申请发货日期</text><text class="value">{{ item.applyShipmentDate
  91 + }}</text>
  92 + </view>
  93 + <view class="row"><text class="label">申请次数</text><text class="value">{{ item.applyCount
  94 + }}</text>
  95 + </view>
  96 + <view class="row"><text class="label">订单类型</text><text class="value">{{ item.orderType
  97 + }}</text></view>
  98 + <view class="row"><text class="label">所属分厂</text><text class="value">{{ item.workshopName }}</text>
  99 + </view>
  100 + <view class="row"><text class="label">客户名称</text><text class="value">{{
  101 + item.customerName }}</text></view>
  102 + <view class="row"><text class="label">发货数量</text><text class="value">{{
  103 + item.quantity
  104 + }}</text>
  105 + </view>
  106 + <view class="row"><text class="label">延期原因</text><text class="value">{{ item.delayReason }}</text>
  107 + </view>
  108 + </view>
  109 + </view>
  110 +
  111 + </view>
  112 +</template>
  113 +<script>
  114 +import { uuid } from '@/utils/uuid.js'
  115 +export default {
  116 + name: 'Product',
  117 + props: {
  118 + title: { type: String, default: '' },
  119 + mode: { type: String, default: 'add' },
  120 + list: { type: Array, default: () => [] },
  121 + },
  122 + data() {
  123 + return {
  124 + items: [],
  125 + collapsedView: false,
  126 + roleCodes: [],
  127 + }
  128 + },
  129 + computed: {
  130 + },
  131 + watch: {
  132 + items: {
  133 + handler() { this.emitChange() },
  134 + deep: true
  135 + },
  136 + list: {
  137 + handler(v) {
  138 + const arr = Array.isArray(v) ? v : []
  139 + this.items = arr.map(x => {
  140 + const it = { ...this.defaultItem(), ...x, collapsed: true }
  141 + return it
  142 + })
  143 + },
  144 + deep: true
  145 + },
  146 + },
  147 + created() {
  148 + const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, collapsed: false })) : [{ ...this.defaultItem(), collapsed: false }]
  149 + this.items = init;
  150 + },
  151 + methods: {
  152 + defaultItem() {
  153 + return {
  154 + purchaseOrderId: uuid(),
  155 + collapsed: false,
  156 + id: '',
  157 + orderNo: '',
  158 + deliveryDate: '',
  159 + applyShipmentDate: '',
  160 + applyCount: '',
  161 + orderType: '',
  162 + workshopName: '',
  163 + customerName: '',
  164 + quantity: '',
  165 + delayReason: '',
  166 + }
  167 + },
  168 +
  169 + onAdd() {
  170 + const obj = this.defaultItem()
  171 + obj.collapsed = true
  172 + this.items.push(obj)
  173 + this.emitChange()
  174 + },
  175 + onRemove(id) {
  176 + if (!id) return
  177 + uni.showModal({
  178 + title: '系统提示',
  179 + content: '是否确定删除选中的产品?',
  180 + confirmText: '确定',
  181 + cancelText: '取消',
  182 + success: (res) => {
  183 + if (res && res.confirm) {
  184 + const i = this.items.findIndex(it => String(it.purchaseOrderId) === String(id))
  185 + if (i >= 0) {
  186 + this.items.splice(i, 1)
  187 + this.emitChange()
  188 + }
  189 + }
  190 + }
  191 + })
  192 + },
  193 + toggleItem(idx) {
  194 + const it = this.items[idx]
  195 + if (!it) return
  196 + it.collapsed = !it.collapsed
  197 + this.$set(this.items, idx, it)
  198 + },
  199 + emitChange() {
  200 + const out = this.items.map(it => ({ ...it }))
  201 + this.$emit('input', out)
  202 + this.$emit('update:value', out)
  203 + this.$emit('change', out)
  204 + },
  205 + onNonNegativeNumberInput(val, item, idx, field) {
  206 + let v = String(val != null ? val : (item && item[field]) || '')
  207 + v = v.replace(/[^0-9.]/g, '')
  208 + v = v.replace(/(\..*)\./g, '$1')
  209 + if (v.startsWith('.')) v = '0' + v
  210 + if (v === '') { item[field] = ''; if (typeof idx === 'number') this.$set(this.items, idx, { ...item }); return }
  211 + const num = Number(v)
  212 + if (isNaN(num) || num < 0) {
  213 + item[field] = '0'
  214 + } else {
  215 + item[field] = v
  216 + }
  217 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  218 + },
  219 + onNonNegativeNumberBlur(item, idx, field) {
  220 + const v = String((item && item[field]) || '')
  221 + const num = Number(v)
  222 + if (isNaN(num) || num < 0) item[field] = '0'
  223 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  224 + },
  225 + onRealNumberInput(val, item, idx, field) {
  226 + let s = String(val != null ? val : (item && item[field]) || '')
  227 + const neg = s.trim().startsWith('-')
  228 + s = s.replace(/[^0-9.\-]/g, '')
  229 + s = s.replace(/(?!^)-/g, '')
  230 + s = s.replace(/(\..*)\./g, '$1')
  231 + if (s.startsWith('.')) s = '0' + s
  232 + if (s.startsWith('-.')) s = '-0.' + s.slice(2)
  233 + if (neg && !s.startsWith('-')) s = '-' + s.replace(/-/g, '')
  234 + item[field] = s
  235 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  236 + },
  237 + onRealNumberBlur(item, idx, field) {
  238 + const s = String((item && item[field]) || '')
  239 + if (s === '') { if (typeof idx === 'number') this.$set(this.items, idx, { ...item }); return }
  240 + const n = Number(s)
  241 + if (isNaN(n)) item[field] = ''
  242 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  243 + },
  244 + toggleViewCollapse() {
  245 + this.collapsedView = !this.collapsedView
  246 + },
  247 + onDeliveryChange(e, item, idx) {
  248 + const getStr = (x) => {
  249 + if (x && x.detail && x.detail.value !== undefined) return x.detail.value
  250 + if (typeof x === 'string') return x
  251 + return item && item.deliveryDate ? item.deliveryDate : ''
  252 + }
  253 + const val = getStr(e)
  254 + if (!val || !this.orderDate) return
  255 + const parse = (s) => {
  256 + const p = String(s).replace(/\//g, '-').split('-')
  257 + const y = Number(p[0])
  258 + const m = Number(p[1])
  259 + const d = Number(p[2])
  260 + return new Date(y, m - 1, d)
  261 + }
  262 + const sel = parse(val)
  263 + const ord = parse(this.orderDate)
  264 + if (!(sel > ord)) {
  265 + item.deliveryDate = ''
  266 + this.$set(this.items, idx, { ...item })
  267 + uni.showToast({ title: '发货日期必须大于订货日期', icon: 'none' })
  268 + }
  269 + }
  270 + }
  271 +}
  272 +</script>
  273 +<style lang="scss" scoped>
  274 +.header {
  275 + background-color: #fff;
  276 + display: flex;
  277 + align-items: center;
  278 + padding: 24rpx 32rpx;
  279 +
  280 + &.bp {
  281 + border-bottom: 1px solid #f0f0f0;
  282 + }
  283 +}
  284 +
  285 +.dot {
  286 + width: 16rpx;
  287 + height: 16rpx;
  288 + background: #3D48A3;
  289 + border-radius: 50%;
  290 + margin-right: 12rpx;
  291 +}
  292 +
  293 +.title {
  294 + font-size: 32rpx;
  295 + color: rgba(0, 0, 0, 0.9);
  296 + font-weight: 600;
  297 +}
  298 +
  299 +.ops {
  300 + margin-left: auto;
  301 +}
  302 +
  303 +.op {
  304 + color: $theme-primary;
  305 + font-size: 28rpx;
  306 + margin-left: 8rpx;
  307 +}
  308 +
  309 +.op1 {
  310 + display: flex;
  311 + align-items: center;
  312 +}
  313 +
  314 +.opAdd {
  315 + color: rgba(0, 0, 0, 0.6);
  316 + width: 40rpx;
  317 + height: 40rpx;
  318 +}
  319 +
  320 +.opCollapse {
  321 + color: rgba(0, 0, 0, 0.6);
  322 + width: 32rpx;
  323 + height: 28rpx;
  324 + margin-right: 16rpx;
  325 +}
  326 +
  327 +::v-deep .uni-list {
  328 + background: transparent;
  329 +
  330 + .uni-list--border-top {
  331 + background-color: transparent !important;
  332 + }
  333 +
  334 + &-item {
  335 + &__extra-text {
  336 + font-size: 32rpx;
  337 + }
  338 +
  339 + &__content-title {
  340 + font-size: 32rpx;
  341 + color: rgba(0, 0, 0, 0.9);
  342 + }
  343 +
  344 + &__container {
  345 + padding: 32rpx;
  346 +
  347 + .uni-easyinput {
  348 +
  349 + .is-disabled {
  350 + background-color: transparent !important;
  351 + }
  352 +
  353 + &__placeholder-class {
  354 + font-size: 32rpx;
  355 + color: rgba(0, 0, 0, 0.4);
  356 + }
  357 +
  358 + &__content {
  359 + border: none;
  360 +
  361 + &-input {
  362 + padding-left: 0 !important;
  363 + height: 48rpx;
  364 + line-height: 48rpx;
  365 + font-size: 32rpx;
  366 + }
  367 +
  368 + .content-clear-icon {
  369 + font-size: 44rpx !important;
  370 + }
  371 + }
  372 + }
  373 +
  374 + .amount-row {
  375 + flex: 1;
  376 + display: flex;
  377 + align-items: center;
  378 +
  379 + .uni-easyinput {
  380 + flex: 1;
  381 + }
  382 +
  383 + .unit {
  384 + margin-left: 16rpx;
  385 + color: rgba(0, 0, 0, 0.9);
  386 + }
  387 + }
  388 +
  389 + .item-title,
  390 + .uni-list-item__content {
  391 + flex: none;
  392 + min-height: 48rpx;
  393 + line-height: 48rpx;
  394 + font-size: 32rpx;
  395 + position: relative;
  396 + width: 210rpx;
  397 + margin-right: 32rpx;
  398 + color: rgba(0, 0, 0, 0.9);
  399 + padding-right: 0;
  400 +
  401 +
  402 + .required {
  403 + color: red;
  404 + position: absolute;
  405 + top: 50%;
  406 + transform: translateY(-50%);
  407 + left: -16rpx;
  408 + }
  409 + }
  410 +
  411 + }
  412 +
  413 + &.select-item {
  414 + &.is-empty {
  415 + .uni-list-item__extra-text {
  416 + color: rgba(0, 0, 0, 0.4) !important;
  417 + }
  418 + }
  419 +
  420 + &.is-filled {
  421 + .uni-list-item__extra-text {
  422 + color: rgba(0, 0, 0, 0.9) !important;
  423 + }
  424 + }
  425 +
  426 + .serial-number-row {
  427 + display: flex;
  428 + align-items: center;
  429 + }
  430 +
  431 + }
  432 +
  433 + &.mgb10 {
  434 + margin-bottom: 20rpx;
  435 + }
  436 +
  437 + }
  438 +
  439 + .title-header {
  440 + background-color: #fff;
  441 + display: flex;
  442 + align-items: center;
  443 + padding: 32rpx 32rpx 22rpx;
  444 +
  445 + &_icon {
  446 + width: 32rpx;
  447 + height: 28rpx;
  448 + margin-right: 16rpx;
  449 + }
  450 +
  451 + span {
  452 + color: rgba(0, 0, 0, 0.9);
  453 + font-size: 32rpx;
  454 + line-height: 44rpx;
  455 + font-weight: 600;
  456 + }
  457 + }
  458 +}
  459 +
  460 +/* 只读 easyinput 根据内容自适应高度 */
  461 +::v-deep .uni-list-item__container {
  462 + align-items: flex-start;
  463 +}
  464 +
  465 +.block-ops {
  466 + display: flex;
  467 + padding: 20rpx 32rpx 20rpx;
  468 + justify-content: space-around;
  469 +}
  470 +
  471 +.del {
  472 + color: #D54941;
  473 + font-size: 28rpx;
  474 + display: flex;
  475 + align-items: center;
  476 +
  477 + image {
  478 + width: 40rpx;
  479 + height: 40rpx;
  480 + }
  481 +}
  482 +
  483 +.toggle {
  484 + color: $theme-primary;
  485 + font-size: 28rpx;
  486 + display: flex;
  487 + align-items: center;
  488 +
  489 + image {
  490 + width: 40rpx;
  491 + height: 40rpx;
  492 + }
  493 +}
  494 +
  495 +.section {
  496 + background: #f1f1f1;
  497 + margin-bottom: 20rpx;
  498 +
  499 + .block {
  500 + background: #ffffff;
  501 + // padding: 32rpx 0;
  502 + margin-bottom: 20rpx;
  503 +
  504 + &:last-child {
  505 + margin-bottom: 0;
  506 + }
  507 + }
  508 +
  509 + .row {
  510 + display: flex;
  511 + // margin-bottom: 24rpx;
  512 + line-height: 32rpx;
  513 + padding: 32rpx;
  514 + border-bottom: 1rpx solid #f2f2f2;
  515 +
  516 +
  517 + &.noneStyle {
  518 + border-bottom: 0;
  519 + border-bottom: none;
  520 + }
  521 +
  522 + &.row-spec {
  523 + align-items: center;
  524 + }
  525 + }
  526 +
  527 + .row:last-child {
  528 + margin-bottom: 0;
  529 + }
  530 +
  531 + .label {
  532 + width: 210rpx;
  533 + margin-right: 32rpx;
  534 + color: rgba(0, 0, 0, 0.9);
  535 + font-size: 32rpx;
  536 + line-height: 48rpx;
  537 + }
  538 +
  539 + .value {
  540 + flex: 1;
  541 + color: rgba(0, 0, 0, 0.9);
  542 + font-size: 32rpx;
  543 + white-space: pre-wrap;
  544 + word-break: break-all;
  545 + line-height: 48rpx;
  546 + }
  547 +
  548 + .value-spec {
  549 + height: 48rpx;
  550 + display: flex;
  551 + align-items: center;
  552 + color: #000000;
  553 +
  554 + &_box {
  555 + position: relative;
  556 + width: 60rpx;
  557 + height: 48rpx;
  558 +
  559 + &_1 {
  560 + font-size: 16rpx;
  561 + position: absolute;
  562 + top: -10rpx;
  563 + left: 0;
  564 + }
  565 +
  566 + &_2 {
  567 + font-size: 16rpx;
  568 + position: absolute;
  569 + bottom: -10rpx;
  570 + left: 0;
  571 + }
  572 + }
  573 +
  574 + &_val {
  575 + font-size: 28rpx;
  576 +
  577 + &.p12 {
  578 + padding-right: 12rpx;
  579 + }
  580 + }
  581 + }
  582 +
  583 + .view-total {
  584 + padding-top: 20rpx;
  585 +
  586 + .head {
  587 + font-size: 32rpx;
  588 + font-weight: 600;
  589 + line-height: 50rpx;
  590 + color: rgba(0, 0, 0, 0.9);
  591 + padding-bottom: 16rpx;
  592 + margin-bottom: 24rpx;
  593 + border-bottom: 1px dashed #E7E7E7;
  594 + }
  595 +
  596 + .row {
  597 + display: flex;
  598 + margin-bottom: 24rpx;
  599 + line-height: 32rpx;
  600 +
  601 + .label {
  602 + width: 180rpx;
  603 + margin-right: 14rpx;
  604 + color: rgba(0, 0, 0, 0.6);
  605 + font-size: 28rpx;
  606 + }
  607 +
  608 + .value {
  609 + flex: 1;
  610 + color: rgba(0, 0, 0, 0.9);
  611 + font-size: 28rpx;
  612 + white-space: pre-wrap;
  613 + word-break: break-all;
  614 + }
  615 + }
  616 + }
  617 +}
  618 +
  619 +
  620 +.view-list {
  621 + padding: 26rpx 32rpx;
  622 + background: #ffffff;
  623 +
  624 + .card {
  625 + background: #f3f3f3;
  626 + border-radius: 16rpx;
  627 + padding: 32rpx 44rpx;
  628 + margin-bottom: 20rpx;
  629 +
  630 + &:last-child {
  631 + margin-bottom: 0;
  632 + }
  633 + }
  634 +
  635 + .row {
  636 + display: flex;
  637 + margin-bottom: 24rpx;
  638 + line-height: 32rpx;
  639 +
  640 + &.row-spec {
  641 + height: 60rpx;
  642 + align-items: center;
  643 + }
  644 + }
  645 +
  646 + .row:last-child {
  647 + margin-bottom: 0;
  648 + }
  649 +
  650 + .label {
  651 + width: 260rpx;
  652 + margin-right: 14rpx;
  653 + color: rgba(0, 0, 0, 0.6);
  654 + font-size: 28rpx;
  655 + }
  656 +
  657 + .value {
  658 + flex: 1;
  659 + color: rgba(0, 0, 0, 0.9);
  660 + font-size: 28rpx;
  661 + white-space: pre-wrap;
  662 + word-break: break-all;
  663 + }
  664 +
  665 + .value-spec {
  666 + height: 60rpx;
  667 + display: flex;
  668 + align-items: center;
  669 + color: #000000;
  670 +
  671 + &_box {
  672 + position: relative;
  673 + width: 60rpx;
  674 + height: 60rpx;
  675 +
  676 + &_1 {
  677 + font-size: 16rpx;
  678 + position: absolute;
  679 + top: 0;
  680 + left: 0;
  681 + }
  682 +
  683 + &_2 {
  684 + font-size: 16rpx;
  685 + position: absolute;
  686 + bottom: 0;
  687 + left: 0;
  688 + }
  689 + }
  690 +
  691 + &_val {
  692 + font-size: 28rpx;
  693 +
  694 + &.p12 {
  695 + padding-right: 12rpx;
  696 + }
  697 + }
  698 + }
  699 +
  700 + .view-total {
  701 + padding-top: 20rpx;
  702 +
  703 + .head {
  704 + font-size: 32rpx;
  705 + font-weight: 600;
  706 + line-height: 50rpx;
  707 + color: rgba(0, 0, 0, 0.9);
  708 + padding-bottom: 16rpx;
  709 + margin-bottom: 24rpx;
  710 + border-bottom: 1px dashed #E7E7E7;
  711 + }
  712 +
  713 + .row {
  714 + display: flex;
  715 + margin-bottom: 24rpx;
  716 + line-height: 32rpx;
  717 +
  718 + .label {
  719 + width: 180rpx;
  720 + margin-right: 14rpx;
  721 + color: rgba(0, 0, 0, 0.6);
  722 + font-size: 28rpx;
  723 + }
  724 +
  725 + .value {
  726 + flex: 1;
  727 + color: rgba(0, 0, 0, 0.9);
  728 + font-size: 28rpx;
  729 + white-space: pre-wrap;
  730 + word-break: break-all;
  731 + }
  732 + }
  733 + }
  734 +}
  735 +</style>
... ...
  1 +<template>
  2 + <view class="page">
  3 + <view class="section">
  4 + <text class="row company">{{ form.deptName }}</text>
  5 + <view class="row"><text class="label">要车日期</text><text class="value">{{ form.applyDate }}</text></view>
  6 + </view>
  7 +
  8 + <!-- 产品 -->
  9 + <view class="section2">
  10 + <Product mode="view" :list="form.delayedShipmentDetailList" />
  11 + </view>
  12 + </view>
  13 +</template>
  14 +
  15 +<script>
  16 +import { getDetailApi } from '@/api/delay_invoice.js'
  17 +import Product from './product.vue'
  18 +
  19 +export default {
  20 + name: 'DelayInvoiceViewer',
  21 + components: { Product },
  22 + props: { id: { type: [String, Number], default: '' } },
  23 + data() {
  24 + return {
  25 + form: {},
  26 + }
  27 + },
  28 + computed: {
  29 + },
  30 + watch: {
  31 + id: {
  32 + immediate: true,
  33 + handler(val) {
  34 + const v = (val !== undefined && val !== null) ? String(val) : ''
  35 + if (v) this.loadDetail(v)
  36 + }
  37 + }
  38 + },
  39 + onLoad(query) {
  40 + },
  41 + methods: {
  42 + async loadDetail(id) {
  43 + try {
  44 + const res = await getDetailApi(id)
  45 + this.form = res.data || {}
  46 + } catch (e) {
  47 + this.form = {}
  48 + }
  49 + },
  50 + getFormValues() {
  51 + const m = this.form || {}
  52 + return JSON.parse(JSON.stringify(m))
  53 + },
  54 + }
  55 +}
  56 +</script>
  57 +
  58 +<style lang="scss" scoped>
  59 +
  60 +.section {
  61 + padding: 32rpx;
  62 + background: #fff;
  63 + margin-bottom: 20rpx;
  64 + position: relative;
  65 +
  66 +}
  67 +
  68 +.row {
  69 + display: flex;
  70 + margin-bottom: 28rpx;
  71 +
  72 + &:last-child {
  73 + margin-bottom: 0;
  74 + }
  75 +
  76 + &.company {
  77 + font-size: 36rpx;
  78 + font-weight: 600;
  79 + color: rgba(0, 0, 0, 0.9);
  80 + padding-top: 10rpx;
  81 + margin-bottom: 32rpx;
  82 + line-height: 50rpx;
  83 + }
  84 +
  85 + .label {
  86 + width: 240rpx;
  87 + line-height: 32rpx;
  88 + font-size: 28rpx;
  89 + color: rgba(0, 0, 0, 0.6);
  90 + }
  91 +
  92 + .value {
  93 + flex: 1;
  94 + line-height: 32rpx;
  95 + font-size: 28rpx;
  96 + color: rgba(0, 0, 0, 0.9);
  97 + text-align: right;
  98 + word-break: break-all;
  99 + }
  100 +}
  101 +
  102 +.title-header {
  103 + background-color: #fff;
  104 + display: flex;
  105 + align-items: center;
  106 + padding: 32rpx 32rpx 22rpx;
  107 + border-bottom: 1rpx dashed #f0f0f0;
  108 +
  109 + &_icon {
  110 + width: 32rpx;
  111 + height: 28rpx;
  112 + margin-right: 16rpx;
  113 + }
  114 +
  115 + span {
  116 + color: rgba(0, 0, 0, 0.9);
  117 + font-size: 32rpx;
  118 + line-height: 44rpx;
  119 + font-weight: 600;
  120 + }
  121 +}
  122 +</style>
... ...
... ... @@ -629,7 +629,7 @@
629 629 font-weight: 600;
630 630 position: absolute;
631 631 top: -32rpx;
632   - right: -32rpx;
  632 + right: -12rpx;
633 633 height: 48rpx;
634 634 line-height: 48rpx;
635 635 color: #fff;
... ...
... ... @@ -399,7 +399,6 @@ export default {
399 399 color: rgba(0, 0, 0, 0.9);
400 400 padding-bottom: 16rpx;
401 401 margin-bottom: 24rpx;
402   - ;
403 402 border-bottom: 1px dashed #E7E7E7;
404 403 }
405 404
... ... @@ -516,7 +515,6 @@ export default {
516 515 color: rgba(0, 0, 0, 0.9);
517 516 padding-bottom: 16rpx;
518 517 margin-bottom: 24rpx;
519   - ;
520 518 border-bottom: 1px dashed #E7E7E7;
521 519 }
522 520
... ...