Commit f771c60967447ea311825b9023c02402e3c6ac2a

Authored by 史婷婷
2 parents dda9b7c5 97d06920

Merge remote-tracking branch 'origin/cjerp-1.0_20260122-sydd' into publish_cjerp

# Conflicts:
#	pages/change_list/add.vue
#	pages/change_list/modify.vue
#	pages/order_list/approve.vue
#	pages/order_list/modify.vue
#	pages/order_list/product.vue
Showing 77 changed files with 8090 additions and 1368 deletions
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <project version="4"> 2 <project version="4">
3 <component name="ChangeListManager"> 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$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
  6 + <change beforePath="$PROJECT_DIR$/pages-business/purchase/config.vue" beforeDir="false" />
  7 + <change beforePath="$PROJECT_DIR$/pages-business/purchase/order/index.vue" beforeDir="false" />
  8 + <change beforePath="$PROJECT_DIR$/pages-business/purchase/order/item/index.vue" beforeDir="false" />
  9 + <change beforePath="$PROJECT_DIR$/pages-business/purchase/order/pay-type/index.vue" beforeDir="false" />
  10 + <change beforePath="$PROJECT_DIR$/pages-business/retail/config.vue" beforeDir="false" />
  11 + <change beforePath="$PROJECT_DIR$/pages-business/sale/config.vue" beforeDir="false" />
  12 + <change beforePath="$PROJECT_DIR$/pages-business/take/config.vue" beforeDir="false" />
  13 + <change beforePath="$PROJECT_DIR$/pages-data/address/index.vue" beforeDir="false" />
  14 + <change beforePath="$PROJECT_DIR$/pages-data/brand/index.vue" beforeDir="false" />
  15 + <change beforePath="$PROJECT_DIR$/pages-data/category/index.vue" beforeDir="false" />
  16 + <change beforePath="$PROJECT_DIR$/pages-data/customer/index.vue" beforeDir="false" />
  17 + <change beforePath="$PROJECT_DIR$/pages-data/logistics/index.vue" beforeDir="false" />
  18 + <change beforePath="$PROJECT_DIR$/pages-data/member/index.vue" beforeDir="false" />
  19 + <change beforePath="$PROJECT_DIR$/pages-data/pay-type/index.vue" beforeDir="false" />
  20 + <change beforePath="$PROJECT_DIR$/pages-data/product/index.vue" beforeDir="false" />
  21 + <change beforePath="$PROJECT_DIR$/pages-data/property/index.vue" beforeDir="false" />
  22 + <change beforePath="$PROJECT_DIR$/pages-data/property/item/index.vue" beforeDir="false" />
  23 + <change beforePath="$PROJECT_DIR$/pages-data/shop/index.vue" beforeDir="false" />
  24 + <change beforePath="$PROJECT_DIR$/pages-data/store-center/index.vue" beforeDir="false" />
  25 + <change beforePath="$PROJECT_DIR$/pages-data/supplier/index.vue" beforeDir="false" />
  26 + <change beforePath="$PROJECT_DIR$/pages.json" beforeDir="false" afterPath="$PROJECT_DIR$/pages.json" afterDir="false" />
  27 + <change beforePath="$PROJECT_DIR$/pages/business/index.vue" beforeDir="false" />
  28 + <change beforePath="$PROJECT_DIR$/pages/common/textview/index.vue" beforeDir="false" />
  29 + <change beforePath="$PROJECT_DIR$/pages/common/webview/index.vue" beforeDir="false" />
  30 + <change beforePath="$PROJECT_DIR$/pages/data/index.vue" beforeDir="false" />
  31 + <change beforePath="$PROJECT_DIR$/pages/mine/help/index.vue" beforeDir="false" />
  32 + <change beforePath="$PROJECT_DIR$/pages/mine/index2.vue" beforeDir="false" />
  33 + </list>
5 <option name="SHOW_DIALOG" value="false" /> 34 <option name="SHOW_DIALOG" value="false" />
6 <option name="HIGHLIGHT_CONFLICTS" value="true" /> 35 <option name="HIGHLIGHT_CONFLICTS" value="true" />
7 <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> 36 <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@@ -50,7 +79,7 @@ @@ -50,7 +79,7 @@
50 <component name="Git.Settings"> 79 <component name="Git.Settings">
51 <option name="RECENT_BRANCH_BY_REPOSITORY"> 80 <option name="RECENT_BRANCH_BY_REPOSITORY">
52 <map> 81 <map>
53 - <entry key="$PROJECT_DIR$" value="publish_cjerp" /> 82 + <entry key="$PROJECT_DIR$" value="test_cjerp" />
54 </map> 83 </map>
55 </option> 84 </option>
56 <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> 85 <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
@@ -63,17 +92,18 @@ @@ -63,17 +92,18 @@
63 <option name="hideEmptyMiddlePackages" value="true" /> 92 <option name="hideEmptyMiddlePackages" value="true" />
64 <option name="showLibraryContents" value="true" /> 93 <option name="showLibraryContents" value="true" />
65 </component> 94 </component>
66 - <component name="PropertiesComponent">{  
67 - &quot;keyToString&quot;: {  
68 - &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,  
69 - &quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,  
70 - &quot;git-widget-placeholder&quot;: &quot;main&quot;,  
71 - &quot;kotlin-language-version-configured&quot;: &quot;true&quot;,  
72 - &quot;last_opened_file_path&quot;: &quot;/Users/zhuyl/Documents/qgutech/erp-mobile&quot;,  
73 - &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,  
74 - &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot; 95 + <component name="PropertiesComponent"><![CDATA[{
  96 + "keyToString": {
  97 + "Git.Branch.Popup.ShowAllRemotes": "true",
  98 + "RunOnceActivity.ShowReadmeOnStart": "true",
  99 + "RunOnceActivity.git.unshallow": "true",
  100 + "git-widget-placeholder": "main",
  101 + "kotlin-language-version-configured": "true",
  102 + "last_opened_file_path": "/Users/zhuyl/Documents/qgutech/erp-mobile",
  103 + "nodejs_package_manager_path": "npm",
  104 + "vue.rearranger.settings.migration": "true"
75 } 105 }
76 -}</component> 106 +}]]></component>
77 <component name="RunManager"> 107 <component name="RunManager">
78 <configuration default="true" type="Applet" factoryName="Applet"> 108 <configuration default="true" type="Applet" factoryName="Applet">
79 <option name="WIDTH" value="400" /> 109 <option name="WIDTH" value="400" />
@@ -175,7 +205,7 @@ @@ -175,7 +205,7 @@
175 <entry key="branch"> 205 <entry key="branch">
176 <value> 206 <value>
177 <list> 207 <list>
178 - <option value="cjerp-1.0_20251220" /> 208 + <option value="origin/cjerp-1.0_20260116" />
179 </list> 209 </list>
180 </value> 210 </value>
181 </entry> 211 </entry>
  1 +import request from '@/utils/request'
  2 +import { ContentTypeEnum } from '@/utils/httpEnum';
  3 +
  4 +const baseUrl = '/confirmationSlip';
  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 updateApi(params) {
  26 + return request({
  27 + url: baseUrl,
  28 + method: 'put',
  29 + data: params,
  30 + contentType: ContentTypeEnum.JSON
  31 + })
  32 +}
  1 +import request from '@/utils/request'
  2 +
  3 +const baseUrl = '/sample/feedback';
  4 +// 查询列表
  5 +export function queryApi(params) {
  6 + return request({
  7 + url: baseUrl + `/query`,
  8 + method: 'get',
  9 + params
  10 + })
  11 +}
  12 +
  13 +// 根据ID查询详情数据
  14 +export function getDetailApi(id) {
  15 + return request({
  16 + url: baseUrl,
  17 + method: 'get',
  18 + params: { id }
  19 + })
  20 +}
  1 +import request from '@/utils/request'
  2 +import { ContentTypeEnum } from '@/utils/httpEnum';
  3 +
  4 +const baseUrl = '/sample/tracking';
  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 updateApi(params) {
  26 + return request({
  27 + url: baseUrl,
  28 + method: 'put',
  29 + data: params,
  30 + contentType: ContentTypeEnum.JSON
  31 + })
  32 +}
@@ -207,7 +207,7 @@ export default { @@ -207,7 +207,7 @@ export default {
207 } 207 }
208 208
209 .label { 209 .label {
210 - max-width: 280rpx; 210 + max-width: 400rpx;
211 margin-right: 20rpx; 211 margin-right: 20rpx;
212 color: rgba(0, 0, 0, 0.6); 212 color: rgba(0, 0, 0, 0.6);
213 font-size: 28rpx; 213 font-size: 28rpx;
@@ -222,7 +222,7 @@ export default { @@ -222,7 +222,7 @@ export default {
222 } 222 }
223 223
224 .label1 { 224 .label1 {
225 - max-width: 280rpx; 225 + max-width: 400rpx;
226 margin-right: 20rpx; 226 margin-right: 20rpx;
227 color: rgba(0, 0, 0, 0.6); 227 color: rgba(0, 0, 0, 0.6);
228 font-size: 32rpx; 228 font-size: 32rpx;
@@ -190,6 +190,7 @@ @@ -190,6 +190,7 @@
190 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount) 190 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount)
191 }}</text></view> 191 }}</text></view>
192 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view> 192 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view>
  193 + <view class="row"><text class="label">是否为试样订单</text><text class="value">{{ item.sampleOrder ? '是' : '否' }}</text></view>
193 </view> 194 </view>
194 </view> 195 </view>
195 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" /> 196 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" />
@@ -207,7 +207,7 @@ export default { @@ -207,7 +207,7 @@ export default {
207 } 207 }
208 208
209 .label { 209 .label {
210 - max-width: 280rpx; 210 + max-width: 400rpx;
211 margin-right: 20rpx; 211 margin-right: 20rpx;
212 color: rgba(0, 0, 0, 0.6); 212 color: rgba(0, 0, 0, 0.6);
213 font-size: 28rpx; 213 font-size: 28rpx;
@@ -222,7 +222,7 @@ export default { @@ -222,7 +222,7 @@ export default {
222 } 222 }
223 223
224 .label1 { 224 .label1 {
225 - max-width: 280rpx; 225 + max-width: 400rpx;
226 margin-right: 20rpx; 226 margin-right: 20rpx;
227 color: rgba(0, 0, 0, 0.6); 227 color: rgba(0, 0, 0, 0.6);
228 font-size: 32rpx; 228 font-size: 32rpx;
@@ -28,7 +28,7 @@ export default { @@ -28,7 +28,7 @@ export default {
28 title: { type: String, default: '请选择' }, 28 title: { type: String, default: '请选择' },
29 // 统一约定:options 为 [{ label: string, value: string|number }] 29 // 统一约定:options 为 [{ label: string, value: string|number }]
30 options: { type: Array, default: () => [] }, 30 options: { type: Array, default: () => [] },
31 - value: { type: [String, Number], default: '' } 31 + value: { type: [String, Number, Boolean], default: '' }
32 }, 32 },
33 data() { 33 data() {
34 return { 34 return {
1 -<template>  
2 -  
3 - <uni-section title="配置项" type="line">  
4 - <view class="form-view">  
5 - <!-- 基础用法,不包含校验规则 -->  
6 -  
7 - </view>  
8 - </uni-section>  
9 -  
10 -</template>  
11 -  
12 -<script>  
13 -  
14 -</script>  
15 -  
16 -<style>  
17 - .top-view{  
18 - padding: 20px;  
19 - }  
20 - .form-view {  
21 - margin-top: 20px;  
22 - padding-left: 5px;  
23 - padding-right: 5px;  
24 - /* display: flex;  
25 - align-items: center; */  
26 - padding-bottom: 20px;  
27 - }  
28 -  
29 - .button-view {  
30 - display: flex;  
31 - align-items: center;  
32 - margin-bottom: 20px;  
33 - }  
34 -  
35 -</style>  
1 -<template>  
2 -  
3 - <uni-section title="配置项" type="line">  
4 - <view class="form-view">  
5 - <!-- 基础用法,不包含校验规则 -->  
6 - <view>零售出库单上的会员是否必填</view>  
7 - <uni-forms-item label="" required>  
8 - <uni-data-checkbox v-model="configFormData.retailOutSheetRequireMember" :localdata="isRequired" />  
9 - </uni-forms-item>  
10 - <view>零售出库单是否需要发货</view>  
11 - <uni-forms-item label="" required>  
12 -  
13 - <uni-data-checkbox v-model="configFormData.retailOutSheetRequireLogistics" :localdata="isRequired" />  
14 - </uni-forms-item>  
15 - <view>零售退货单上的会员是否必填</view>  
16 - <uni-forms-item label="" required>  
17 -  
18 - <uni-data-checkbox v-model="configFormData.retailReturnRequireMember" :localdata="isRequired" />  
19 - </uni-forms-item>  
20 - <view>零售退货单是否关联零售出库单</view>  
21 - <uni-forms-item label="" required>  
22 -  
23 - <uni-data-checkbox v-model="configFormData.retailReturnRequireOutStock" :localdata="isRequired" />  
24 - </uni-forms-item>  
25 - <view>零售退货单是否多次关联零售出库单</view>  
26 - <uni-forms-item label="" required>  
27 -  
28 - <uni-data-checkbox v-model="configFormData.retailReturnMultipleRelateOutStock" :localdata="isRequired" />  
29 - </uni-forms-item>  
30 -  
31 - </uni-forms>  
32 - <view class="button-view">  
33 - <button class="btn-view-button" @click="submit" type="primary" size="mini">保存</button>  
34 - <button class="btn-view-button" @click="cancel" type="primary" size="mini">取消</button>  
35 - </view>  
36 - </view>  
37 - </uni-section>  
38 -  
39 -</template>  
40 -  
41 -<script>  
42 -  
43 -</script>  
44 -  
45 -<style>  
46 - .top-view{  
47 - padding: 20px;  
48 - }  
49 - .form-view {  
50 - margin-top: 20px;  
51 - padding-left: 5px;  
52 - padding-right: 5px;  
53 - /* display: flex;  
54 - align-items: center; */  
55 - padding-bottom: 20px;  
56 - }  
57 -  
58 - .button-view {  
59 - display: flex;  
60 - align-items: center;  
61 - margin-bottom: 20px;  
62 - }  
63 -  
64 -</style>  
1 -<template>  
2 -  
3 - <uni-section title="配置项" type="line">  
4 - <view class="form-view">  
5 -  
6 - </view>  
7 - </uni-section>  
8 -  
9 -</template>  
10 -  
11 -<script>  
12 -  
13 -</script>  
14 -  
15 -<style>  
16 - .top-view{  
17 - padding: 20px;  
18 - }  
19 - .form-view {  
20 - margin-top: 20px;  
21 - padding-left: 5px;  
22 - padding-right: 5px;  
23 - /* display: flex;  
24 - align-items: center; */  
25 - padding-bottom: 20px;  
26 - }  
27 -  
28 - .button-view {  
29 - display: flex;  
30 - align-items: center;  
31 - margin-bottom: 20px;  
32 - }  
33 -  
34 -</style>  
1 -<template>  
2 -  
3 - <uni-section title="配置项" type="line">  
4 - <view class="form-view">  
5 -  
6 - </view>  
7 - </uni-section>  
8 -  
9 -</template>  
10 -  
11 -<script>  
12 -  
13 -</script>  
14 -  
15 -<style>  
16 - .top-view{  
17 - padding: 20px;  
18 - }  
19 - .form-view {  
20 - margin-top: 20px;  
21 - padding-left: 5px;  
22 - padding-right: 5px;  
23 - /* display: flex;  
24 - align-items: center; */  
25 - padding-bottom: 20px;  
26 - }  
27 -  
28 - .button-view {  
29 - display: flex;  
30 - align-items: center;  
31 - margin-bottom: 20px;  
32 - }  
33 -  
34 -</style>  
@@ -28,12 +28,6 @@ @@ -28,12 +28,6 @@
28 } 28 }
29 }, 29 },
30 { 30 {
31 - "path": "pages/mine/index2",  
32 - "style": {  
33 - "navigationBarTitleText": "我的2"  
34 - }  
35 - },  
36 - {  
37 "path": "pages/mine/info/index", 31 "path": "pages/mine/info/index",
38 "style": { 32 "style": {
39 "navigationBarTitleText": "个人信息" 33 "navigationBarTitleText": "个人信息"
@@ -784,126 +778,70 @@ @@ -784,126 +778,70 @@
784 "navigationBarBackgroundColor": "#ffffff", 778 "navigationBarBackgroundColor": "#ffffff",
785 "navigationBarTextStyle": "black" 779 "navigationBarTextStyle": "black"
786 } 780 }
787 - }  
788 - ],  
789 - "subPackages": [  
790 - {  
791 - "root": "pages-business",  
792 - "pages": [  
793 - {  
794 - "path": "purchase/config",  
795 - "style": {  
796 - "navigationBarTitleText": "采购设置"  
797 - }  
798 - },  
799 - {  
800 - "path": "purchase/order/index",  
801 - "style": {  
802 - "navigationBarTitleText": "采购订单"  
803 - }  
804 - },  
805 - {  
806 - "path": "retail/config",  
807 - "style": {  
808 - "navigationBarTitleText": "零售设置"  
809 - }  
810 - },  
811 - {  
812 - "path": "sale/config",  
813 - "style": {  
814 - "navigationBarTitleText": "销售设置"  
815 - }  
816 - },  
817 - {  
818 - "path": "take/config",  
819 - "style": {  
820 - "navigationBarTitleText": "盘点设置"  
821 - }  
822 - }  
823 - ]  
824 - },  
825 - {  
826 - "root": "pages-data",  
827 - "pages": [  
828 - {  
829 - "path": "address/index",  
830 - "style": {  
831 - "navigationBarTitleText": "地址管理"  
832 - }  
833 - },  
834 - {  
835 - "path": "brand/index",  
836 - "style": {  
837 - "navigationBarTitleText": "品牌管理"  
838 - }  
839 - },  
840 - {  
841 - "path": "category/index",  
842 - "style": {  
843 - "navigationBarTitleText": "分类管理"  
844 - }  
845 - },  
846 - {  
847 - "path": "customer/index",  
848 - "style": {  
849 - "navigationBarTitleText": "客户管理"  
850 - }  
851 - },  
852 - {  
853 - "path": "logistics/index",  
854 - "style": {  
855 - "navigationBarTitleText": "物流管理"  
856 - }  
857 - },  
858 - {  
859 - "path": "member/index",  
860 - "style": {  
861 - "navigationBarTitleText": "会员管理"  
862 - }  
863 - },  
864 - {  
865 - "path": "pay-type/index",  
866 - "style": {  
867 - "navigationBarTitleText": "支付方式"  
868 - }  
869 - },  
870 - {  
871 - "path": "product/index",  
872 - "style": {  
873 - "navigationBarTitleText": "产品管理"  
874 - }  
875 - },  
876 - {  
877 - "path": "property/index",  
878 - "style": {  
879 - "navigationBarTitleText": "商品属性"  
880 - }  
881 - },  
882 - {  
883 - "path": "property/item/index",  
884 - "style": {  
885 - "navigationBarTitleText": "属性项"  
886 - }  
887 - },  
888 - {  
889 - "path": "shop/index",  
890 - "style": {  
891 - "navigationBarTitleText": "店铺管理"  
892 - }  
893 - },  
894 - {  
895 - "path": "store-center/index",  
896 - "style": {  
897 - "navigationBarTitleText": "门店管理"  
898 - }  
899 - },  
900 - {  
901 - "path": "supplier/index",  
902 - "style": {  
903 - "navigationBarTitleText": "供应商管理"  
904 - }  
905 - }  
906 - ] 781 + },
  782 + {
  783 + "path": "pages/confirmation_form/index",
  784 + "style": {
  785 + "navigationBarTitleText": "产品试样确认单",
  786 + "navigationBarBackgroundColor": "#ffffff",
  787 + "navigationBarTextStyle": "black"
  788 + }
  789 + },
  790 + {
  791 + "path": "pages/confirmation_form/detail",
  792 + "style": {
  793 + "navigationBarTitleText": "产品试样确认单详情",
  794 + "navigationBarBackgroundColor": "#ffffff",
  795 + "navigationBarTextStyle": "black"
  796 + }
  797 + },
  798 + {
  799 + "path": "pages/confirmation_form/modify",
  800 + "style": {
  801 + "navigationBarTitleText": "编辑产品试样确认单",
  802 + "navigationBarBackgroundColor": "#ffffff",
  803 + "navigationBarTextStyle": "black"
  804 + }
  805 + },
  806 + {
  807 + "path": "pages/follow_up_form/index",
  808 + "style": {
  809 + "navigationBarTitleText": "产品试样结果跟踪单",
  810 + "navigationBarBackgroundColor": "#ffffff",
  811 + "navigationBarTextStyle": "black"
  812 + }
  813 + },
  814 + {
  815 + "path": "pages/follow_up_form/detail",
  816 + "style": {
  817 + "navigationBarTitleText": "产品试样结果跟踪单详情",
  818 + "navigationBarBackgroundColor": "#ffffff",
  819 + "navigationBarTextStyle": "black"
  820 + }
  821 + },
  822 + {
  823 + "path": "pages/follow_up_form/modify",
  824 + "style": {
  825 + "navigationBarTitleText": "编辑产品试样结果跟踪单",
  826 + "navigationBarBackgroundColor": "#ffffff",
  827 + "navigationBarTextStyle": "black"
  828 + }
  829 + },
  830 + {
  831 + "path": "pages/feedback_form/index",
  832 + "style": {
  833 + "navigationBarTitleText": "产品试样结果反馈单",
  834 + "navigationBarBackgroundColor": "#ffffff",
  835 + "navigationBarTextStyle": "black"
  836 + }
  837 + },
  838 + {
  839 + "path": "pages/feedback_form/detail",
  840 + "style": {
  841 + "navigationBarTitleText": "产品试样结果反馈单详情",
  842 + "navigationBarBackgroundColor": "#ffffff",
  843 + "navigationBarTextStyle": "black"
  844 + }
907 } 845 }
908 ], 846 ],
909 "tabBar": { 847 "tabBar": {
1 -<template>  
2 - <view class="work-container">  
3 - <!-- 轮播图 -->  
4 - <uni-swiper-dot class="uni-swiper-dot-box" :info="data" :current="current" field="content">  
5 - <swiper class="swiper-box" :current="swiperDotIndex" @change="changeSwiper">  
6 - <swiper-item v-for="(item, index) in data" :key="index">  
7 - <view class="swiper-item" @click="clickBannerItem(item)">  
8 - <image :src="item.image" mode="aspectFill" :draggable="false" />  
9 - </view>  
10 - </swiper-item>  
11 - </swiper>  
12 - </uni-swiper-dot>  
13 -  
14 - <!-- 宫格组件 -->  
15 - <uni-section title="采购管理" type="line">  
16 - <HR style="border:1 dashed #eeeeff" width="100%" color='#eeeeff' SIZE='1' />  
17 -  
18 - <view class="grid-body">  
19 - <uni-grid :column="4" :showBorder="false" @change="changeGrid">  
20 -  
21 - <uni-grid-item :index=1>  
22 - <view class="grid-item-box">  
23 - <!-- <uni-icons color="#007AFF" type="gift" size="30"></uni-icons> -->  
24 - <view class="cuIcon-settings text-pink icon"></view>  
25 - <text class="text">参数配置</text>  
26 - </view>  
27 - </uni-grid-item>  
28 - <uni-grid-item :index=2>  
29 - <view class="grid-item-box">  
30 - <!-- <uni-icons color="#007AFF" type="list" size="30"></uni-icons> -->  
31 - <view class="cuIcon-sort text-pink icon"></view>  
32 - <text class="text">采购订单</text>  
33 - </view>  
34 - </uni-grid-item>  
35 - <uni-grid-item :index=3>  
36 - <view class="grid-item-box">  
37 - <!-- <uni-icons color="#007AFF" type="color" size="30"></uni-icons> -->  
38 - <view class="cuIcon-newshot text-pink icon"></view>  
39 - <text class="text">采购入库</text>  
40 - </view>  
41 - </uni-grid-item>  
42 - <uni-grid-item :index=4>  
43 - <view class="grid-item-box">  
44 - <!-- <uni-icons color="#007AFF" type="flag" size="30"></uni-icons> -->  
45 - <view class="cuIcon-exit text-pink icon"></view>  
46 - <text class="text">采购退货</text>  
47 - </view>  
48 - </uni-grid-item>  
49 - </uni-grid>  
50 - </view>  
51 - </uni-section>  
52 - <uni-section title="销售管理" type="line">  
53 - <HR style="border:1 dashed #eeeeff" width="100%" color='#eeeeff' SIZE='1' />  
54 - <view class="grid-body">  
55 - <uni-grid :column="4" :showBorder="false" @change="changeGrid">  
56 - <uni-grid-item :index=5>  
57 - <view class="grid-item-box">  
58 - <!-- <uni-icons color="#007AFF" type="person-filled" size="30"></uni-icons> -->  
59 -  
60 - <view class="cuIcon-settings text-yellow icon"></view>  
61 - <text class="text">参数配置</text>  
62 - </view>  
63 - </uni-grid-item>  
64 - <uni-grid-item :index=6>  
65 - <view class="grid-item-box">  
66 - <!-- <uni-icons color="#007AFF" type="staff-filled" size="30"></uni-icons> -->  
67 - <view class="cuIcon-sort text-yellow icon"></view>  
68 - <text class="text">销售订单</text>  
69 - </view>  
70 - </uni-grid-item>  
71 - <uni-grid-item :index=7>  
72 - <view class="grid-item-box">  
73 - <!-- <uni-icons color="#007AFF" type="auth" size="30"></uni-icons> -->  
74 - <view class="cuIcon-text text-yellow icon"></view>  
75 - <text class="text">销售出库</text>  
76 - </view>  
77 - </uni-grid-item>  
78 - <uni-grid-item :index=8>  
79 - <view class="grid-item-box">  
80 - <!-- <uni-icons color="#007AFF" type="home" size="30"></uni-icons> -->  
81 - <view class="cuIcon-exit text-yellow icon"></view>  
82 - <text class="text">销售退货</text>  
83 - </view>  
84 - </uni-grid-item>  
85 -  
86 - </uni-grid>  
87 - </view>  
88 - </uni-section>  
89 - <uni-section title="零售管理" type="line">  
90 - <HR style="border:1 dashed #eeeeff" width="100%" color='#eeeeff' SIZE='1' />  
91 - <view class="grid-body">  
92 - <uni-grid :column="4" :showBorder="false" @change="changeGrid">  
93 - <uni-grid-item :index=9>  
94 - <view class="grid-item-box">  
95 - <!-- <uni-icons color="#007AFF" type="shop" size="30"></uni-icons> -->  
96 - <view class="cuIcon-settings text-green icon"></view>  
97 - <text class="text">参数配置</text>  
98 - </view>  
99 - </uni-grid-item>  
100 - <uni-grid-item :index=10>  
101 - <view class="grid-item-box">  
102 - <!-- <uni-icons color="#007AFF" type="wallet" size="30"></uni-icons> -->  
103 - <view class="cuIcon-text text-green icon"></view>  
104 - <text class="text">零售出库</text>  
105 - </view>  
106 - </uni-grid-item>  
107 - <uni-grid-item :index=11>  
108 - <view class="grid-item-box">  
109 - <!-- <uni-icons color="#007AFF" type="map-pin-ellipse" size="30"></uni-icons> -->  
110 - <view class="cuIcon-exit text-green icon"></view>  
111 - <text class="text">零售退货</text>  
112 - </view>  
113 - </uni-grid-item>  
114 - </uni-grid>  
115 - </view>  
116 - </uni-section>  
117 - <uni-section title="库存管理" type="line">  
118 - <HR style="border:1 dashed #eeeeff" width="100%" color='#eeeeff' SIZE='1' />  
119 - <view class="grid-body">  
120 - <uni-grid :column="4" :showBorder="false" @change="changeGrid">  
121 - <uni-grid-item :index=12>  
122 - <view class="grid-item-box">  
123 - <!-- <uni-icons color="#007AFF" type="link" size="30"></uni-icons> -->  
124 - <view class="cuIcon-punch text-brown icon"></view>  
125 - <text class="text">商品库存</text>  
126 - </view>  
127 - </uni-grid-item>  
128 - <uni-grid-item :index=13>  
129 - <view class="grid-item-box">  
130 - <!-- <uni-icons type="wallet-filled" size="30"></uni-icons> -->  
131 - <view class="cuIcon-form text-brown icon"></view>  
132 - <text class="text">变动记录</text>  
133 - </view>  
134 - </uni-grid-item>  
135 - <uni-grid-item :index=14>  
136 - <view class="grid-item-box">  
137 - <!-- <uni-icons type="wallet-filled" size="30"></uni-icons> -->  
138 - <view class="cuIcon-edit text-brown icon"></view>  
139 - <text class="text">数量调整</text>  
140 - </view>  
141 - </uni-grid-item>  
142 - <uni-grid-item :index=15>  
143 - <view class="grid-item-box">  
144 - <view class="cuIcon-recharge text-brown icon"></view>  
145 - <text class="text">成本调整</text>  
146 - </view>  
147 - </uni-grid-item>  
148 - <uni-grid-item :index=16>  
149 - <view class="grid-item-box">  
150 - <view class="cuIcon-info text-brown icon"></view>  
151 - <text class="text">调整原因</text>  
152 - </view>  
153 - </uni-grid-item>  
154 - <uni-grid-item :index=17>  
155 - <view class="grid-item-box">  
156 - <view class="cuIcon-camerarotate text-brown icon"></view>  
157 - <text class="text">仓库调拨</text>  
158 - </view>  
159 - </uni-grid-item>  
160 - </uni-grid>  
161 - </view>  
162 - </uni-section>  
163 - <uni-section title="盘点管理" type="line">  
164 - <HR style="border:1 dashed #eeeeff" width="100%" color='#eeeeff' SIZE='1' />  
165 - <view class="grid-body">  
166 - <uni-grid :column="4" :showBorder="false" @change="changeGrid">  
167 - <uni-grid-item :index=18>  
168 - <view class="grid-item-box">  
169 - <!-- <uni-icons color="#007AFF" type="link" size="30"></uni-icons> -->  
170 - <view class="cuIcon-settings text-blue icon"></view>  
171 - <text class="text">参数配置</text>  
172 - </view>  
173 - </uni-grid-item>  
174 - <uni-grid-item :index=19>  
175 - <view class="grid-item-box">  
176 - <!-- <uni-icons type="wallet-filled" size="30"></uni-icons> -->  
177 - <view class="cuIcon-roundcheck text-blue icon"></view>  
178 - <text class="text">预盘点单</text>  
179 - </view>  
180 - </uni-grid-item>  
181 - <uni-grid-item :index=20>  
182 - <view class="grid-item-box">  
183 - <!-- <uni-icons type="wallet-filled" size="30"></uni-icons> -->  
184 - <view class="cuIcon-post text-blue icon"></view>  
185 - <text class="text">盘点任务</text>  
186 - </view>  
187 - </uni-grid-item>  
188 - <uni-grid-item :index=21>  
189 - <view class="grid-item-box">  
190 - <!-- <uni-icons type="wallet-filled" size="30"></uni-icons> -->  
191 - <view class="cuIcon-same text-blue icon"></view>  
192 - <text class="text">盘点单管理</text>  
193 - </view>  
194 - </uni-grid-item>  
195 -  
196 - </uni-grid>  
197 - </view>  
198 - </uni-section>  
199 - <view>  
200 - <uni-popup ref="alertDialog" type="dialog">  
201 - <uni-popup-dialog type="info" cancelText="关闭" confirmText="确定" title="专业版源代码" content="专业版源代码">  
202 - <view><image src="../../static/images/wx.jpg" style="width: 250px;height: 250px;"></image></view>  
203 - </uni-popup-dialog>  
204 - </uni-popup>  
205 - </view>  
206 - </view>  
207 -</template>  
208 -  
209 -<script>  
210 - export default {  
211 - data() {  
212 - return {  
213 - current: 0,  
214 - swiperDotIndex: 0,  
215 - data: [{  
216 - image: 'http://xy.wecando21cn.com/static/images/banner/banner01.jpg'  
217 - },  
218 - {  
219 - image: 'http://xy.wecando21cn.com/static/images/banner/banner02.jpg'  
220 - },  
221 - {  
222 - image: 'http://xy.wecando21cn.com/static/images/banner/banner03.jpg'  
223 - }  
224 - ],  
225 - }  
226 - },  
227 - methods: {  
228 - clickBannerItem(item) {  
229 - console.info(item)  
230 - },  
231 - changeSwiper(e) {  
232 - this.current = e.detail.current  
233 - },  
234 - changeGrid(e) {  
235 - this.$refs.alertDialog.open('center');  
236 - }  
237 - }  
238 - }  
239 -</script>  
240 -  
241 -<style lang="scss">  
242 - /* #ifndef APP-NVUE */  
243 - page {  
244 - display: flex;  
245 - flex-direction: column;  
246 - box-sizing: border-box;  
247 - background-color: #fff;  
248 - min-height: 100%;  
249 - height: auto;  
250 - }  
251 -  
252 - view {  
253 - font-size: 14px;  
254 - line-height: inherit;  
255 - }  
256 -  
257 - .uni-icons {  
258 - color: #007AFF;  
259 - }  
260 -  
261 - /* #endif */  
262 -  
263 - .text {  
264 - text-align: center;  
265 - font-size: 26rpx;  
266 - margin-top: 10rpx;  
267 - }  
268 -  
269 - .grid-item-box {  
270 - flex: 1;  
271 - /* #ifndef APP-NVUE */  
272 - display: flex;  
273 - /* #endif */  
274 - flex-direction: column;  
275 - align-items: center;  
276 - justify-content: center;  
277 - padding: 15px 0;  
278 - }  
279 -  
280 - .uni-margin-wrap {  
281 - width: 690rpx;  
282 - width: 100%;  
283 - ;  
284 - }  
285 -  
286 - .swiper {  
287 - height: 300rpx;  
288 - }  
289 -  
290 - .swiper-box {  
291 - height: 150px;  
292 - }  
293 -  
294 - .swiper-item {  
295 - /* #ifndef APP-NVUE */  
296 - display: flex;  
297 - /* #endif */  
298 - flex-direction: column;  
299 - justify-content: center;  
300 - align-items: center;  
301 - color: #fff;  
302 - height: 300rpx;  
303 - line-height: 300rpx;  
304 - }  
305 -  
306 - @media screen and (min-width: 500px) {  
307 - .uni-swiper-dot-box {  
308 - width: 400px;  
309 - /* #ifndef APP-NVUE */  
310 - margin: 0 auto;  
311 - /* #endif */  
312 - margin-top: 8px;  
313 - }  
314 -  
315 - .image {  
316 - width: 100%;  
317 - }  
318 - }  
319 -  
320 - .icon {  
321 - font-size: 28px;  
322 - }  
323 -  
324 - .text {  
325 - display: block;  
326 - font-size: 13px;  
327 - margin: 8px 0px;  
328 - }  
329 -</style>  
@@ -53,9 +53,9 @@ @@ -53,9 +53,9 @@
53 <uni-easyinput v-model="form.priceListNo" placeholder="请输入价格表编号" :inputBorder="false" /> 53 <uni-easyinput v-model="form.priceListNo" placeholder="请输入价格表编号" :inputBorder="false" />
54 </template> 54 </template>
55 </uni-list-item> 55 </uni-list-item>
56 - <uni-list-item title="开票情况"> 56 + <uni-list-item title="开票要求">
57 <template v-slot:footer> 57 <template v-slot:footer>
58 - <uni-easyinput v-model="form.invoicingStatus" placeholder="请输入开票情况" :inputBorder="false" /> 58 + <uni-easyinput v-model="form.invoicingStatus" placeholder="请输入开票要求" :inputBorder="false" />
59 </template> 59 </template>
60 </uni-list-item> 60 </uni-list-item>
61 <uni-list-item class="amount-item"> 61 <uni-list-item class="amount-item">
@@ -216,7 +216,7 @@ export default { @@ -216,7 +216,7 @@ export default {
216 const m = res.data || {} 216 const m = res.data || {}
217 const next = { ...this.form, ...m } 217 const next = { ...this.form, ...m }
218 next.id = m.id || m.code || id 218 next.id = m.id || m.code || id
219 - next.purchaseOrderLineList = Array.isArray(m.purchaseOrderLineList) ? m.purchaseOrderLineList.map(x => ({ 219 + next.purchaseOrderLineList = Array.isArray(m.purchaseOrderLineList) ? m.purchaseOrderLineList.map(x => ({
220 ...x, 220 ...x,
221 assessmentExceedsAgreement: Number(x.assessmentExceedsAgreement || 0).toFixed(2) || 0.00, 221 assessmentExceedsAgreement: Number(x.assessmentExceedsAgreement || 0).toFixed(2) || 0.00,
222 })) : [] 222 })) : []
@@ -27,7 +27,7 @@ @@ -27,7 +27,7 @@
27 27
28 <view class="section"> 28 <view class="section">
29 <view class="row"><text class="label">价格表编号</text><text class="value">{{ form.priceListNo }}</text></view> 29 <view class="row"><text class="label">价格表编号</text><text class="value">{{ form.priceListNo }}</text></view>
30 - <view class="row"><text class="label">开票情况</text><text class="value">{{ form.invoicingStatus }}</text></view> 30 + <view class="row"><text class="label">开票要求</text><text class="value">{{ form.invoicingStatus }}</text></view>
31 <view class="row"><text class="label">运费</text><text class="value">{{ form.shippingCost }}</text></view> 31 <view class="row"><text class="label">运费</text><text class="value">{{ form.shippingCost }}</text></view>
32 <view class="row"><text class="label">执行标准</text><text class="value">{{ getDicName('APPLICABLE_STANDARD', 32 <view class="row"><text class="label">执行标准</text><text class="value">{{ getDicName('APPLICABLE_STANDARD',
33 form.executionStandard, dicOptions.APPLICABLE_STANDARD) }}</text></view> 33 form.executionStandard, dicOptions.APPLICABLE_STANDARD) }}</text></view>
@@ -52,9 +52,9 @@ @@ -52,9 +52,9 @@
52 <uni-easyinput v-model="form.priceListNo" placeholder="请输入价格表编号" :inputBorder="false" /> 52 <uni-easyinput v-model="form.priceListNo" placeholder="请输入价格表编号" :inputBorder="false" />
53 </template> 53 </template>
54 </uni-list-item> 54 </uni-list-item>
55 - <uni-list-item title="开票情况"> 55 + <uni-list-item title="开票要求">
56 <template v-slot:footer> 56 <template v-slot:footer>
57 - <uni-easyinput v-model="form.invoicingStatus" placeholder="请输入开票情况" :inputBorder="false" /> 57 + <uni-easyinput v-model="form.invoicingStatus" placeholder="请输入开票要求" :inputBorder="false" />
58 </template> 58 </template>
59 </uni-list-item> 59 </uni-list-item>
60 <uni-list-item class="amount-item"> 60 <uni-list-item class="amount-item">
@@ -212,7 +212,7 @@ export default { @@ -212,7 +212,7 @@ export default {
212 const next = { ...this.form, ...m } 212 const next = { ...this.form, ...m }
213 next.id = m.id || m.code || id; 213 next.id = m.id || m.code || id;
214 next.purchaseOrderId = m.orderId || ''; 214 next.purchaseOrderId = m.orderId || '';
215 - next.purchaseOrderLineList = Array.isArray(m.afterChangeSpecList) ? m.afterChangeSpecList.map(x => ({ 215 + next.purchaseOrderLineList = Array.isArray(m.afterChangeSpecList) ? m.afterChangeSpecList.map(x => ({
216 ...x, 216 ...x,
217 assessmentExceedsAgreement: Number(x.assessmentExceedsAgreement || 0).toFixed(2) || 0.00, 217 assessmentExceedsAgreement: Number(x.assessmentExceedsAgreement || 0).toFixed(2) || 0.00,
218 })) : [] 218 })) : []
@@ -27,7 +27,7 @@ @@ -27,7 +27,7 @@
27 27
28 <view class="section"> 28 <view class="section">
29 <view class="row"><text class="label">价格表编号</text><text class="value">{{ form.priceListNo }}</text></view> 29 <view class="row"><text class="label">价格表编号</text><text class="value">{{ form.priceListNo }}</text></view>
30 - <view class="row"><text class="label">开票情况</text><text class="value">{{ form.invoicingStatus }}</text></view> 30 + <view class="row"><text class="label">开票要求</text><text class="value">{{ form.invoicingStatus }}</text></view>
31 <view class="row"><text class="label">运费</text><text class="value">{{ form.shippingCost }}</text></view> 31 <view class="row"><text class="label">运费</text><text class="value">{{ form.shippingCost }}</text></view>
32 <view class="row"><text class="label">执行标准</text><text class="value">{{ getDicName('APPLICABLE_STANDARD', 32 <view class="row"><text class="label">执行标准</text><text class="value">{{ getDicName('APPLICABLE_STANDARD',
33 form.executionStandard, dicOptions.APPLICABLE_STANDARD) }}</text></view> 33 form.executionStandard, dicOptions.APPLICABLE_STANDARD) }}</text></view>
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <view class="detail-page">
  5 + <view v-if="isEditAll">
  6 + <view class="section">
  7 + <uni-list-item title="订货单位" class="no-border-top">
  8 + <template v-slot:footer>
  9 + <view class="readonly-text">{{ form.orderingUnitName }}</view>
  10 + </template>
  11 + </uni-list-item>
  12 + <uni-list-item class="select-item" :class="form.sampleTypeName ? 'is-filled' : 'is-empty'"
  13 + clickable @click="openSheet('sampleType')" :rightText="form.sampleTypeName || '请选择'"
  14 + showArrow>
  15 + <template v-slot:body>
  16 + <view class="item-title"><text>试样种类</text></view>
  17 + </template>
  18 + </uni-list-item>
  19 + <uni-list-item class="select-item" :class="form.customerTypeName ? 'is-filled' : 'is-empty'"
  20 + clickable @click="openSheet('customerType')" :rightText="form.customerTypeName || '请选择'"
  21 + showArrow>
  22 + <template v-slot:body>
  23 + <view class="item-title"><text>客户类型</text></view>
  24 + </template>
  25 + </uni-list-item>
  26 + <uni-list-item title="生产厂">
  27 + <template v-slot:footer>
  28 + <view class="readonly-text">{{ form.workshopName }}</view>
  29 + </template>
  30 + </uni-list-item>
  31 + <uni-list-item title="所属品种">
  32 + <template v-slot:footer>
  33 + <view class="readonly-text">{{ form.belongingBreed }}</view>
  34 + </template>
  35 + </uni-list-item>
  36 + <uni-list-item title="原供货同行">
  37 + <template v-slot:footer>
  38 + <uni-easyinput v-model="form.originalSupplierPeer" placeholder="请输入原供货同行"
  39 + :inputBorder="false" />
  40 + </template>
  41 + </uni-list-item>
  42 + </view>
  43 +
  44 + <!-- 产品 -->
  45 + <view class="section2">
  46 + <!-- mode="add" 允许编辑 -->
  47 + <Product mode="add" :list="initPurchaseOrderLineList" @change="purchaseOrderLineListChange"
  48 + :provideSamplesOptions="provideSamplesOptions"
  49 + :clearParametersOptions="clearParametersOptions" />
  50 + </view>
  51 +
  52 + <view class="section3">
  53 + <view class="view-total">
  54 + <view class="head">合计</view>
  55 + <view class="row">
  56 + <view class="row2">
  57 + <text class="label">数量</text><text class="value">{{ form.totalQuantity }}</text>
  58 + </view>
  59 + </view>
  60 + </view>
  61 + </view>
  62 +
  63 + <view class="section2">
  64 +
  65 + <uni-list-item class="select-item"
  66 + :class="form.sampleQuantityRegulationName ? 'is-filled' : 'is-empty'" clickable
  67 + @click="openSheet('sampleQuantityRegulation')"
  68 + :rightText="form.sampleQuantityRegulationName || '请选择'" showArrow>
  69 + <template v-slot:body>
  70 + <view class="item-title"><text>本次试样数量是否超规定</text></view>
  71 + </template>
  72 + </uni-list-item>
  73 +
  74 + <uni-list-item class="select-item"
  75 + :class="form.specificationQuantityRegulationName ? 'is-filled' : 'is-empty'" clickable
  76 + @click="openSheet('specificationQuantityRegulation')"
  77 + :rightText="form.specificationQuantityRegulationName || '请选择'" showArrow>
  78 + <template v-slot:body>
  79 + <view class="item-title"><text>试样规格个数是否超规定</text></view>
  80 + </template>
  81 + </uni-list-item>
  82 +
  83 + <uni-list-item title="试样次数">
  84 + <template v-slot:footer>
  85 + <uni-easyinput type="textarea" v-model="form.sampleFrequency" placeholder="请输入试样次数"
  86 + :inputBorder="false" />
  87 + </template>
  88 + </uni-list-item>
  89 +
  90 + <uni-list-item title="前期不合格描述">
  91 + <template v-slot:footer>
  92 + <uni-easyinput type="textarea" v-model="form.earlyNonconformityDescription"
  93 + placeholder="请输入前期不合格描述" :inputBorder="false" />
  94 + </template>
  95 + </uni-list-item>
  96 +
  97 + </view>
  98 + </view>
  99 + <view v-else class="detail-section">
  100 + <view class="section">
  101 + <text class="row company">{{ form.orderingUnitName }}</text>
  102 + <view :class="['status', `status_${form.status}`]" />
  103 + <view class="row"><text class="label">试样种类</text><text class="value">{{ form.sampleTypeName
  104 + }}</text></view>
  105 + <view class="row"><text class="label">客户类型</text><text class="value">{{ form.customerTypeName
  106 + }}</text></view>
  107 + <view class="row"><text class="label">分厂</text><text class="value">{{ form.workshopName
  108 + }}</text></view>
  109 + <view class="row"><text class="label">所属品种</text><text class="value">{{ form.belongingBreed
  110 + }}</text></view>
  111 + <view class="row"><text class="label">原供货同行</text><text class="value">{{
  112 + form.originalSupplierPeer }}</text>
  113 + </view>
  114 + </view>
  115 +
  116 + <!-- 产品 -->
  117 + <view class="section2">
  118 + <Product mode="view" :list="form.productSampleConfirmationSlipDetailList" />
  119 + </view>
  120 +
  121 + <view class="section3">
  122 + <view class="view-total">
  123 + <view class="head">合计</view>
  124 + <view class="row">
  125 + <view class="row2">
  126 + <text class="label">数量</text><text class="value">{{ form.totalQuantity }}</text>
  127 + </view>
  128 + </view>
  129 + </view>
  130 + </view>
  131 +
  132 + <view class="section">
  133 + <view class="row"><text class="label">数量</text><text class="value">{{ form.totalQuantity
  134 + }}</text></view>
  135 + <view class="row"><text class="label">本次试样数量是否超规定</text><text class="value">{{
  136 + form.sampleQuantityRegulation ?
  137 + '是' : '否' }}</text></view>
  138 + <view class="row"><text class="label">试样规格个数是否超规定</text><text class="value">{{
  139 + form.specificationQuantityRegulation ? '是' : '否' }}</text></view>
  140 + <view class="row"><text class="label">试样次数</text><text class="value">{{ form.sampleFrequency
  141 + }}</text></view>
  142 + <uni-list-item class="row-2" :class="form.earlyNonconformityDescription ? 'is-filled' : 'is-empty'" v-if="isEditEarlyNonconformityDescription" title="前期不合格描述">
  143 + <template v-slot:footer>
  144 + <uni-easyinput type="textarea" v-model="form.earlyNonconformityDescription"
  145 + placeholder="请输入前期不合格描述" :inputBorder="false" />
  146 + </template>
  147 + </uni-list-item>
  148 + <view v-else class="row"><text class="label">前期不合格描述</text><text class="value">{{
  149 + form.earlyNonconformityDescription
  150 + }}</text></view>
  151 + </view>
  152 + </view>
  153 +
  154 +
  155 + </view>
  156 + </scroll-view>
  157 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options"
  158 + v-model="sheet.value" @confirm="onSheetConfirm" />
  159 + </view>
  160 +</template>
  161 +
  162 +<script>
  163 +import { getDetailApi } from '@/api/confirmation_form.js'
  164 +import Product from './product.vue'
  165 +import {
  166 + getDicByCodes
  167 +} from '@/utils/dic'
  168 +import SingleSelectSheet from '@/components/single-select/index.vue'
  169 +// 办事处内勤:可编辑 (编辑时的所有字段)
  170 +// 办事处主管:只能编辑 :前期不合格描述
  171 +// 其他人 :只能查看
  172 +export default {
  173 + name: 'ConfirmationFormApprove',
  174 + components: { Product, SingleSelectSheet },
  175 + props: { id: { type: [String, Number], default: '' } },
  176 + data() {
  177 + return {
  178 + form: {},
  179 + initPurchaseOrderLineList: [],
  180 + roleCodes: [],
  181 + canEditSupplementary: false,
  182 + isEditAll: false,
  183 + isEditEarlyNonconformityDescription: false,
  184 + sheet: { visible: false, title: '请选择', options: [], value: '', field: '' },
  185 + dicOptions: {
  186 + ENTERPRISE_TYPE: [], // 客户类型
  187 + SAMPLE_TYPE: [], // 试样种类
  188 + CLEAR_PARAMETERS: [], // 是否提供明确参数
  189 + PROVIDE_SAMPLES: [], // 是否提供样品
  190 + },
  191 + enterpriseTypeLocal: [], // 客户类型
  192 + sampleTypeLocal: [], // 试样种类
  193 + provideSamplesOptions: [], // 是否提供样品
  194 + clearParametersOptions: [], // 是否提供明确参数
  195 + }
  196 + },
  197 + computed: {
  198 + },
  199 + watch: {
  200 + id: {
  201 + immediate: true,
  202 + handler(val) {
  203 + const v = (val !== undefined && val !== null) ? String(val) : ''
  204 + if (v) {
  205 + this.loadDetail(v);
  206 + this.loadAllDicData()
  207 + this.getRoleInfo();
  208 + }
  209 + }
  210 + }
  211 + },
  212 + onLoad(query) {
  213 +
  214 + },
  215 + methods: {
  216 + getRoleInfo() {
  217 + this.roleCodes = this.$store.getters.roleCodes || [];
  218 + console.log('roleCodes', this.roleCodes)
  219 + // 办事处内勤:可编辑 (编辑时的所有字段) bscnq
  220 + this.isEditAll = this.roleCodes.includes('bscnq');
  221 + // 办事处主管:只能编辑 :前期不合格描述 bsczg
  222 + this.isEditEarlyNonconformityDescription = this.roleCodes.includes('bsczg');
  223 + },
  224 + async loadDetail(id) {
  225 + try {
  226 + const res = await getDetailApi(id)
  227 + const m = res.data || {}
  228 + const next = { ...this.form, ...m }
  229 + // 确保ID存在
  230 + next.id = m.id || id
  231 + next.sampleQuantityRegulationName = m.sampleQuantityRegulation === true ? '是' : '否'
  232 + next.specificationQuantityRegulationName = m.specificationQuantityRegulation === true ? '是' : '否'
  233 + // 映射列表
  234 + // 注意:详情返回的是 productSampleConfirmationSlipDetailList,需要赋值给 initPurchaseOrderLineList 以便 Product 组件初始化
  235 + // 且需要处理字段兼容性,确保 Product 组件能正确显示和编辑
  236 + const lines = Array.isArray(m.productSampleConfirmationSlipDetailList) ? m.productSampleConfirmationSlipDetailList.map(x => ({
  237 + ...x,
  238 + // 确保 Product 组件需要的字段存在
  239 + // Product组件使用: quantity(需发), shippedQuantity(实发), supplementaryQuantity(需求补货), salesPrice(单价)
  240 + // 详情接口返回的字段应该已经包含了这些,如果有差异需要在此处转换
  241 + // 注意:add.vue中 onRelateConfirm 做了映射,这里是回显,通常直接使用即可
  242 + })) : []
  243 +
  244 + this.form = next;
  245 + this.initPurchaseOrderLineList = lines;
  246 + } catch (e) {
  247 + this.form = {}
  248 + }
  249 + },
  250 + loadAllDicData() {
  251 + const dicCodes = ['ENTERPRISE_TYPE', 'SAMPLE_TYPE', 'CLEAR_PARAMETERS', 'PROVIDE_SAMPLES']
  252 + return getDicByCodes(dicCodes).then(results => {
  253 + this.dicOptions.ENTERPRISE_TYPE = results.ENTERPRISE_TYPE.data || []
  254 + this.dicOptions.SAMPLE_TYPE = results.SAMPLE_TYPE.data || []
  255 + this.dicOptions.CLEAR_PARAMETERS = results.CLEAR_PARAMETERS.data || []
  256 + this.dicOptions.PROVIDE_SAMPLES = results.PROVIDE_SAMPLES.data || []
  257 +
  258 + this.enterpriseTypeLocal = (this.dicOptions.ENTERPRISE_TYPE || []).map(it => ({
  259 + value: it.code,
  260 + label: it.name
  261 + }))
  262 + this.sampleTypeLocal = (this.dicOptions.SAMPLE_TYPE || []).map(it => ({
  263 + value: it.code,
  264 + label: it.name
  265 + }))
  266 + this.provideSamplesOptions = (this.dicOptions.PROVIDE_SAMPLES || []).map(it => ({
  267 + value: it.code,
  268 + label: it.name
  269 + }))
  270 + this.clearParametersOptions = (this.dicOptions.CLEAR_PARAMETERS || []).map(it => ({
  271 + value: it.code,
  272 + label: it.name
  273 + }))
  274 + }).catch(() => {
  275 + this.dicOptions = {
  276 + ENTERPRISE_TYPE: [], // 客户类型
  277 + SAMPLE_TYPE: [], // 试样种类
  278 + CLEAR_PARAMETERS: [], // 是否提供明确参数
  279 + PROVIDE_SAMPLES: [], // 是否提供样品
  280 + }
  281 + this.enterpriseTypeLocal = []
  282 + this.sampleTypeLocal = []
  283 + this.provideSamplesOptions = []
  284 + this.clearParametersOptions = []
  285 + })
  286 + },
  287 + calculateSummary(list) {
  288 + const summary = (list || []).reduce((acc, it) => {
  289 + const qty = Number(it.supplementaryQuantity) || 0
  290 + const shipped = Number(it.shippedQuantity) || 0
  291 + const orderQty = Number(it.quantity) || 0
  292 + acc.totalSupplementaryQuantity += qty
  293 + acc.totalShippedQuantity += shipped
  294 + acc.totalQuantity += orderQty
  295 + return acc
  296 + }, { totalQuantity: 0, totalShippedQuantity: 0, totalSupplementaryQuantity: 0 })
  297 +
  298 + const fixedTotalQuantity = Number(summary.totalQuantity.toFixed(2))
  299 + const fixedTotalShippedQuantity = Number(summary.totalShippedQuantity.toFixed(2))
  300 + const fixedTotalSupplementaryQuantity = Number(summary.totalSupplementaryQuantity.toFixed(2))
  301 + this.form.totalQuantity = fixedTotalQuantity
  302 + this.form.totalShippedQuantity = fixedTotalShippedQuantity
  303 + this.form.totalSupplementaryQuantity = fixedTotalSupplementaryQuantity
  304 + },
  305 + purchaseOrderLineListChange(data) {
  306 + const list = Array.isArray(data) ? data : []
  307 + this.form.productSampleConfirmationSlipDetailList = list
  308 + },
  309 + getFormValues() {
  310 + delete this.form.status;
  311 + const m = this.form || {}
  312 + return JSON.parse(JSON.stringify(m))
  313 + },
  314 + // 审批-通过:校验表单
  315 + checkForm() {
  316 + return true
  317 + },
  318 + openSheet(field) {
  319 + let options = []
  320 + let title = ''
  321 + let value = ''
  322 +
  323 + if (field === 'sampleType') {
  324 + title = '试样种类'
  325 + options = this.sampleTypeLocal
  326 + value = this.form.sampleType
  327 + } else if (field === 'customerType') {
  328 + title = '客户类型'
  329 + options = this.enterpriseTypeLocal
  330 + value = this.form.customerType
  331 + } else if (field === 'sampleQuantityRegulation') {
  332 + title = '本次试样数量是否超规定'
  333 + options = [{ value: true, label: '是' }, { value: false, label: '否' }]
  334 + value = this.form.sampleQuantityRegulation
  335 + } else if (field === 'specificationQuantityRegulation') {
  336 + title = '试样规格个数是否超规定'
  337 + options = [{ value: true, label: '是' }, { value: false, label: '否' }]
  338 + value = this.form.specificationQuantityRegulation
  339 + }
  340 +
  341 + const match = options.find(o => String(o.value) === String(value))
  342 + this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
  343 + },
  344 + onSheetConfirm({ value, label }) {
  345 + const field = this.sheet.field
  346 + this.form[field] = value
  347 + this.form[field + 'Name'] = label
  348 + this.sheet.visible = false
  349 + },
  350 + }
  351 +}
  352 +</script>
  353 +
  354 +<style lang="scss" scoped>
  355 +.page {
  356 + display: flex;
  357 + flex-direction: column;
  358 + height: 100vh;
  359 +}
  360 +
  361 +.scroll {
  362 + flex: 1;
  363 + background: #f3f3f3;
  364 +}
  365 +
  366 +.detail-page {
  367 + padding-bottom: 150rpx;
  368 +}
  369 +
  370 +.section {
  371 + padding: 32rpx;
  372 + background: #fff;
  373 + margin-bottom: 20rpx;
  374 + position: relative;
  375 +
  376 +}
  377 +
  378 +.row {
  379 + display: flex;
  380 + margin-bottom: 28rpx;
  381 +
  382 + &:last-child {
  383 + margin-bottom: 0;
  384 + }
  385 +
  386 + &.company {
  387 + font-size: 36rpx;
  388 + font-weight: 600;
  389 + color: rgba(0, 0, 0, 0.9);
  390 + padding-top: 10rpx;
  391 + margin-bottom: 32rpx;
  392 + line-height: 50rpx;
  393 + }
  394 +
  395 + .label {
  396 + width: 240rpx;
  397 + line-height: 32rpx;
  398 + font-size: 28rpx;
  399 + color: rgba(0, 0, 0, 0.6);
  400 + }
  401 +
  402 + .value {
  403 + flex: 1;
  404 + line-height: 32rpx;
  405 + font-size: 28rpx;
  406 + color: rgba(0, 0, 0, 0.9);
  407 + text-align: right;
  408 + word-break: break-all;
  409 + }
  410 +}
  411 +
  412 +.row-2 {
  413 + display: flex;
  414 + margin-bottom: 28rpx;
  415 +
  416 + &:last-child {
  417 + margin-bottom: 0;
  418 + }
  419 +
  420 + &.company {
  421 + font-size: 36rpx;
  422 + font-weight: 600;
  423 + color: rgba(0, 0, 0, 0.9);
  424 + padding-top: 10rpx;
  425 + margin-bottom: 32rpx;
  426 + line-height: 50rpx;
  427 + }
  428 +
  429 + .label {
  430 + width: 240rpx;
  431 + line-height: 32rpx;
  432 + font-size: 28rpx;
  433 + color: rgba(0, 0, 0, 0.6);
  434 + }
  435 +
  436 + .value {
  437 + flex: 1;
  438 + line-height: 32rpx;
  439 + font-size: 28rpx;
  440 + color: rgba(0, 0, 0, 0.9);
  441 + text-align: right;
  442 + word-break: break-all;
  443 + }
  444 +}
  445 +
  446 +
  447 +.title-header {
  448 + background-color: #fff;
  449 + display: flex;
  450 + align-items: center;
  451 + padding: 32rpx 32rpx 22rpx;
  452 + border-bottom: 1rpx dashed #f0f0f0;
  453 +
  454 + &_icon {
  455 + width: 32rpx;
  456 + height: 28rpx;
  457 + margin-right: 16rpx;
  458 + }
  459 +
  460 + span {
  461 + color: rgba(0, 0, 0, 0.9);
  462 + font-size: 32rpx;
  463 + line-height: 44rpx;
  464 + font-weight: 600;
  465 + }
  466 +}
  467 +
  468 +.section3 {
  469 + padding: 0 32rpx;
  470 + background-color: #fff;
  471 + margin-bottom: 20rpx;
  472 +}
  473 +
  474 +.view-total {
  475 + padding: 20rpx 0;
  476 +
  477 + .head {
  478 + font-size: 32rpx;
  479 + font-weight: 600;
  480 + line-height: 50rpx;
  481 + color: rgba(0, 0, 0, 0.9);
  482 + padding-bottom: 16rpx;
  483 + margin-bottom: 24rpx;
  484 + border-bottom: 1px dashed #E7E7E7;
  485 + }
  486 +
  487 + .row {
  488 + display: flex;
  489 + margin-bottom: 24rpx;
  490 + line-height: 32rpx;
  491 +
  492 + .row2 {
  493 + width: 50%;
  494 + }
  495 +
  496 + .label {
  497 + width: 180rpx;
  498 + margin-right: 14rpx;
  499 + color: rgba(0, 0, 0, 0.6);
  500 + font-size: 28rpx;
  501 + }
  502 +
  503 + .value {
  504 + flex: 1;
  505 + color: rgba(0, 0, 0, 0.9);
  506 + font-size: 28rpx;
  507 + white-space: pre-wrap;
  508 + word-break: break-all;
  509 + }
  510 + }
  511 +}
  512 +
  513 +::v-deep .no-border-top {
  514 + .uni-list--border::after {
  515 + background-color: transparent;
  516 + }
  517 +}
  518 +
  519 +.detail-section {
  520 +
  521 + .section {
  522 + padding: 32rpx;
  523 + background: #fff;
  524 + margin-bottom: 20rpx;
  525 + position: relative;
  526 +
  527 +
  528 + }
  529 +
  530 + .row {
  531 + display: flex;
  532 + margin-bottom: 28rpx;
  533 +
  534 + &:last-child {
  535 + margin-bottom: 0;
  536 + }
  537 +
  538 + &.company {
  539 + font-size: 36rpx;
  540 + font-weight: 600;
  541 + color: rgba(0, 0, 0, 0.9);
  542 + padding-top: 10rpx;
  543 + margin-bottom: 32rpx;
  544 + line-height: 50rpx;
  545 + }
  546 +
  547 + .label {
  548 + max-width: 400rpx;
  549 + margin-right: 20rpx;
  550 + line-height: 32rpx;
  551 + font-size: 28rpx;
  552 + color: rgba(0, 0, 0, 0.6);
  553 + }
  554 +
  555 + .value {
  556 + flex: 1;
  557 + line-height: 32rpx;
  558 + font-size: 28rpx;
  559 + color: rgba(0, 0, 0, 0.9);
  560 + text-align: right;
  561 + word-break: break-all;
  562 + }
  563 + }
  564 +
  565 + .title-header {
  566 + background-color: #fff;
  567 + display: flex;
  568 + align-items: center;
  569 + padding: 32rpx 32rpx 22rpx;
  570 + border-bottom: 1rpx dashed #f0f0f0;
  571 +
  572 + &_icon {
  573 + width: 32rpx;
  574 + height: 28rpx;
  575 + margin-right: 16rpx;
  576 + }
  577 +
  578 + span {
  579 + color: rgba(0, 0, 0, 0.9);
  580 + font-size: 32rpx;
  581 + line-height: 44rpx;
  582 + font-weight: 600;
  583 + }
  584 + }
  585 +
  586 + .section2 {
  587 + background: #f1f1f1;
  588 + }
  589 +
  590 +
  591 + .section3 {
  592 + padding: 0 32rpx;
  593 + background-color: #fff;
  594 + margin: 20rpx 0;
  595 + }
  596 +
  597 + .view-total {
  598 + padding-bottom: 20rpx;
  599 +
  600 + .head {
  601 + font-size: 32rpx;
  602 + font-weight: 600;
  603 + line-height: 50rpx;
  604 + color: rgba(0, 0, 0, 0.9);
  605 + padding-bottom: 16rpx;
  606 + margin-bottom: 24rpx;
  607 + border-bottom: 1px dashed #E7E7E7;
  608 + }
  609 +
  610 + .row {
  611 + display: flex;
  612 + margin-bottom: 24rpx;
  613 + line-height: 32rpx;
  614 +
  615 + .row2 {
  616 + width: 50%;
  617 + }
  618 +
  619 + .label {
  620 + width: 180rpx;
  621 + margin-right: 14rpx;
  622 + color: rgba(0, 0, 0, 0.6);
  623 + font-size: 28rpx;
  624 + }
  625 +
  626 + .value {
  627 + flex: 1;
  628 + color: rgba(0, 0, 0, 0.9);
  629 + font-size: 28rpx;
  630 + white-space: pre-wrap;
  631 + word-break: break-all;
  632 + }
  633 + }
  634 + }
  635 +}
  636 +::v-deep .row-2 {
  637 + .uni-list-item__container {
  638 + padding-left: 0;
  639 + padding-right: 0;
  640 + }
  641 +}
  642 +</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.orderingUnitName }}</text>
  7 + <view :class="['status', `status_${form.status}`]" />
  8 + <view class="row"><text class="label">试样种类</text><text class="value">{{ form.sampleTypeName }}</text></view>
  9 + <view class="row"><text class="label">客户类型</text><text class="value">{{ form.customerTypeName }}</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.belongingBreed }}</text></view>
  12 + <view class="row"><text class="label">原供货同行</text><text class="value">{{ form.originalSupplierPeer }}</text>
  13 + </view>
  14 + </view>
  15 +
  16 + <!-- 产品 -->
  17 + <view class="section2">
  18 + <Product mode="view" :list="form.productSampleConfirmationSlipDetailList" />
  19 + </view>
  20 +
  21 + <view class="section3">
  22 + <view class="view-total">
  23 + <view class="head">合计</view>
  24 + <view class="row">
  25 + <view class="row2">
  26 + <text class="label">数量</text><text class="value">{{ form.totalQuantity }}</text>
  27 + </view>
  28 + </view>
  29 + </view>
  30 + </view>
  31 +
  32 + <view class="section">
  33 + <view class="row"><text class="label">数量</text><text class="value">{{ form.totalQuantity }}</text></view>
  34 + <view class="row"><text class="label">本次试样数量是否超规定</text><text class="value">{{ form.sampleQuantityRegulation ?
  35 + '是' : '否' }}</text></view>
  36 + <view class="row"><text class="label">试样规格个数是否超规定</text><text class="value">{{
  37 + form.specificationQuantityRegulation ? '是' : '否' }}</text></view>
  38 + <view class="row"><text class="label">试样次数</text><text class="value">{{ form.sampleFrequency }}</text></view>
  39 + <view class="row"><text class="label">前期不合格描述</text><text class="value">{{ form.earlyNonconformityDescription
  40 + }}</text></view>
  41 + </view>
  42 + </view>
  43 + </scroll-view>
  44 + <detail-buttons :buttons="displayButtons" @click="handleButtonClick" />
  45 + </view>
  46 +</template>
  47 +
  48 +<script>
  49 +import { getDetailApi } from '@/api/confirmation_form.js'
  50 +import Product from './product.vue'
  51 +import DetailButtons from '@/components/detail-buttons/index.vue'
  52 +
  53 +export default {
  54 + name: 'ConfirmationFormDetail',
  55 + components: { Product, DetailButtons },
  56 + data() {
  57 + return {
  58 + form: {},
  59 + buttons: [
  60 + { text: '编辑', visible: true, variant: 'outline', event: 'edit' },
  61 + { text: '审核详情', visible: true, variant: 'outline', event: 'auditDetail' },
  62 + { text: '审核', visible: true, variant: 'primary', event: 'audit' },
  63 + ]
  64 + }
  65 + },
  66 + computed: {
  67 + statusFlags() {
  68 + const m = this.form || {}
  69 + const e = String(m.status || '')
  70 + // showAudit 这个字段就是后端自己判断的 制单人所在区域 所有人 权限
  71 + return {
  72 + canEdit: !e && m.showAudit || false,
  73 + canAudit: e === 'AUDIT' && m.showExamine || false,
  74 + canAuditDetail: !!e || false,
  75 + }
  76 + },
  77 + displayButtons() {
  78 + const f = this.statusFlags
  79 + return [
  80 + { ...this.buttons[0], visible: f.canEdit }, // 不需要额外的角色权限
  81 + { ...this.buttons[1], visible: f.canAuditDetail && this.$auth.hasPermi('sample-order:confirmation-form:review') },
  82 + { ...this.buttons[2], visible: f.canAudit && this.$auth.hasPermi('sample-order:confirmation-form:approve') },
  83 + ]
  84 + }
  85 + },
  86 + onLoad(query) {
  87 + const id = (query && (query.id || query.code)) || ''
  88 + if (id) this.loadDetail(id)
  89 + },
  90 + methods: {
  91 + async loadDetail(id) {
  92 + try {
  93 + const res = await getDetailApi(id)
  94 + this.form = res.data || {}
  95 + } catch (e) {
  96 + this.form = {}
  97 + }
  98 + },
  99 + handleButtonClick(btn) {
  100 + if (!btn || btn.disabled) return
  101 + const map = {
  102 + edit: () => this.onEdit(),
  103 + auditDetail: () => this.onAuditDetail(),
  104 + audit: () => this.onAudit(),
  105 + }
  106 + const fn = map[btn.event]
  107 + if (typeof fn === 'function') fn()
  108 + },
  109 + onEdit() {
  110 + const id = this.form.id || this.form.code
  111 + if (id) uni.navigateTo({ url: `/pages/confirmation_form/modify?id=${id}` })
  112 + },
  113 + onAuditDetail() {
  114 + uni.setStorageSync('sourceBusinessId', this.form.id)
  115 + uni.navigateTo({ url: '/pages/flow/audit_detail' })
  116 + },
  117 + onAudit() {
  118 + uni.setStorageSync('sourceBusinessId', this.form.id)
  119 + uni.navigateTo({ url: '/pages/flow/audit' })
  120 + },
  121 +
  122 + }
  123 +}
  124 +</script>
  125 +
  126 +<style lang="scss" scoped>
  127 +.page {
  128 + display: flex;
  129 + flex-direction: column;
  130 + height: 100vh;
  131 +}
  132 +
  133 +.scroll {
  134 + flex: 1;
  135 + background: #f3f3f3;
  136 +}
  137 +
  138 +.detail-page {
  139 + padding-bottom: 150rpx;
  140 +}
  141 +
  142 +.section {
  143 + padding: 32rpx;
  144 + background: #fff;
  145 + margin-bottom: 20rpx;
  146 + position: relative;
  147 +
  148 + .status {
  149 + position: absolute;
  150 + top: 16rpx;
  151 + right: 52rpx;
  152 + width: 180rpx;
  153 + height: 146rpx;
  154 + background-repeat: no-repeat;
  155 + background-size: 100% 100%;
  156 + background-position: center;
  157 +
  158 + &_AUDIT {
  159 + background-image: url('~@/static/images/dev_manage/status_1.png');
  160 + }
  161 +
  162 + &_PASS {
  163 + background-image: url('~@/static/images/dev_manage/status_2.png');
  164 + }
  165 +
  166 + &_REFUSE {
  167 + background-image: url('~@/static/images/dev_manage/status_3.png');
  168 + }
  169 +
  170 + &_CANCEL {
  171 + background-image: url('~@/static/images/dev_manage/status_4.png');
  172 + }
  173 +
  174 + }
  175 +}
  176 +
  177 +.row {
  178 + display: flex;
  179 + margin-bottom: 28rpx;
  180 +
  181 + &:last-child {
  182 + margin-bottom: 0;
  183 + }
  184 +
  185 + &.company {
  186 + font-size: 36rpx;
  187 + font-weight: 600;
  188 + color: rgba(0, 0, 0, 0.9);
  189 + padding-top: 10rpx;
  190 + margin-bottom: 32rpx;
  191 + line-height: 50rpx;
  192 + }
  193 +
  194 + .label {
  195 + max-width: 400rpx;
  196 + margin-right: 20rpx;
  197 + line-height: 32rpx;
  198 + font-size: 28rpx;
  199 + color: rgba(0, 0, 0, 0.6);
  200 + }
  201 +
  202 + .value {
  203 + flex: 1;
  204 + line-height: 32rpx;
  205 + font-size: 28rpx;
  206 + color: rgba(0, 0, 0, 0.9);
  207 + text-align: right;
  208 + word-break: break-all;
  209 + }
  210 +}
  211 +
  212 +.title-header {
  213 + background-color: #fff;
  214 + display: flex;
  215 + align-items: center;
  216 + padding: 32rpx 32rpx 22rpx;
  217 + border-bottom: 1rpx dashed #f0f0f0;
  218 +
  219 + &_icon {
  220 + width: 32rpx;
  221 + height: 28rpx;
  222 + margin-right: 16rpx;
  223 + }
  224 +
  225 + span {
  226 + color: rgba(0, 0, 0, 0.9);
  227 + font-size: 32rpx;
  228 + line-height: 44rpx;
  229 + font-weight: 600;
  230 + }
  231 +}
  232 +
  233 +.section2 {
  234 + background: #f1f1f1;
  235 +}
  236 +
  237 +
  238 +.section3 {
  239 + padding: 0 32rpx;
  240 + background-color: #fff;
  241 + margin: 20rpx 0;
  242 +}
  243 +
  244 +.view-total {
  245 + padding-bottom: 20rpx;
  246 +
  247 + .head {
  248 + font-size: 32rpx;
  249 + font-weight: 600;
  250 + line-height: 50rpx;
  251 + color: rgba(0, 0, 0, 0.9);
  252 + padding-bottom: 16rpx;
  253 + margin-bottom: 24rpx;
  254 + border-bottom: 1px dashed #E7E7E7;
  255 + }
  256 +
  257 + .row {
  258 + display: flex;
  259 + margin-bottom: 24rpx;
  260 + line-height: 32rpx;
  261 +
  262 + .row2 {
  263 + width: 50%;
  264 + }
  265 +
  266 + .label {
  267 + width: 180rpx;
  268 + margin-right: 14rpx;
  269 + color: rgba(0, 0, 0, 0.6);
  270 + font-size: 28rpx;
  271 + }
  272 +
  273 + .value {
  274 + flex: 1;
  275 + color: rgba(0, 0, 0, 0.9);
  276 + font-size: 28rpx;
  277 + white-space: pre-wrap;
  278 + word-break: break-all;
  279 + }
  280 + }
  281 +}
  282 +</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 + <text :class="['status', `status_${item.status}`]">{{ filterStatus(item.status) }}</text>
  24 + </view>
  25 + <view class="info-row">
  26 + <text>试样种类</text><text>{{ item.sampleTypeName || '-' }}</text>
  27 + </view>
  28 + <view class="info-row">
  29 + <text>生产厂</text><text>{{ item.workshopName || '-' }}</text>
  30 + </view>
  31 + <view class="info-row">
  32 + <text>客户类型</text><text>{{ item.customerTypeName || '-' }}</text>
  33 + </view>
  34 + </view>
  35 + </template>
  36 + </card-list>
  37 + </view>
  38 +
  39 +
  40 +
  41 + <!-- 筛选弹框 -->
  42 + <filter-modal :visible.sync="filterVisible" :value.sync="filterForm" title="筛选" @reset="onFilterReset"
  43 + @confirm="onFilterConfirm">
  44 + <template v-slot="{ model }">
  45 + <view class="filter-form">
  46 + <view class="form-item">
  47 + <view class="label">生产厂</view>
  48 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  49 + v-model="model.workshopId" @change="onWorkshopChange" :localdata="workshopOptions" />
  50 + </view>
  51 + <view class="form-item">
  52 + <view class="label">审核状态</view>
  53 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  54 + v-model="model.status" @change="onStatusChange" :localdata="statusLocal" />
  55 + </view>
  56 + <view class="form-item">
  57 + <view class="label">试样种类</view>
  58 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  59 + v-model="model.sampleType" @change="onSampleTypeChange" :localdata="sampleTypeLocal" />
  60 + </view>
  61 + <view class="form-item">
  62 + <view class="label">客户类型</view>
  63 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  64 + v-model="model.customerType" @change="onEnterpriseTypeChange" :localdata="enterpriseTypeLocal" />
  65 + </view>
  66 + </view>
  67 + </template>
  68 + </filter-modal>
  69 + </view>
  70 +</template>
  71 +
  72 +<script>
  73 +import CardList from '@/components/card/index.vue'
  74 +import FilterModal from '@/components/filter/index.vue'
  75 +import { workshopQueryApi } from '@/api/devManage.js'
  76 +import SingleSelectSheet from '@/components/single-select/index.vue'
  77 +import {
  78 + queryApi
  79 +} from '@/api/confirmation_form.js'
  80 +import {
  81 + getDicByCodes
  82 +} from '@/utils/dic'
  83 +
  84 +export default {
  85 + components: {
  86 + CardList,
  87 + FilterModal,
  88 + SingleSelectSheet
  89 + },
  90 + data() {
  91 + return {
  92 + searchKeyword: '',
  93 + searchKeywordDebounced: '',
  94 + tabs: [],
  95 + // 给到 card 的筛选值
  96 + query: {
  97 + status: '',
  98 + workshopId: '',
  99 + sampleType: '',
  100 + customerType: '',
  101 + },
  102 + extraParams: {},
  103 +
  104 + // 批量选择
  105 + rowKey: 'id',
  106 + currentItems: [],
  107 +
  108 + // 筛选弹框
  109 + filterVisible: false,
  110 + filterForm: {
  111 + status: '',
  112 + workshopId: '',
  113 + sampleType: '',
  114 + customerType: '',
  115 + },
  116 + dicOptions: {
  117 + AUDIT_STATUS: [], // 审核
  118 + ENTERPRISE_TYPE: [], // 客户类型
  119 + SAMPLE_TYPE: [], // 试样种类
  120 + },
  121 + statusLocal: [],
  122 + enterpriseTypeLocal: [], // 客户类型
  123 + sampleTypeLocal: [], // 试样种类
  124 + workshopOptions: [],
  125 + }
  126 + },
  127 + computed: {
  128 + extraCombined() {
  129 + return {
  130 + orderingUnitName: this.searchKeywordDebounced || undefined
  131 + }
  132 + }
  133 + },
  134 + watch: {
  135 + extraCombined: {
  136 + deep: true,
  137 + handler(v) {
  138 + this.extraParams = v
  139 + },
  140 + immediate: true
  141 + },
  142 +
  143 + },
  144 + created() {
  145 + this.loadAllDicData()
  146 + this.loadWorkshopOptions()
  147 + },
  148 + onLoad() { },
  149 + // 页面触底兜底:当页面自身滚动到底部时,转调卡片组件加载更多
  150 + onReachBottom() {
  151 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) {
  152 + this.$refs.cardRef.onLoadMore()
  153 + }
  154 + },
  155 + beforeDestroy() {
  156 + if (this.searchDebounceTimer) {
  157 + clearTimeout(this.searchDebounceTimer)
  158 + this.searchDebounceTimer = null
  159 + }
  160 + },
  161 + methods: {
  162 + async loadWorkshopOptions() {
  163 + try {
  164 + const res = await workshopQueryApi({ pageIndex: 1, pageSize: 9999 })
  165 + const list = (res && res.data && res.data.datas) || []
  166 + this.workshopOptions = list.map(it => ({ text: it.name || it.workshopName || '', value: it.id || it.workshopId || '' }))
  167 + } catch (e) {
  168 + this.workshopOptions = []
  169 + }
  170 + },
  171 + onCardLoaded({
  172 + items
  173 + }) {
  174 + this.currentItems = items
  175 + },
  176 + onCardError() {
  177 + uni.showToast({
  178 + title: '列表加载失败',
  179 + icon: 'none'
  180 + })
  181 + },
  182 + // 输入实时搜索:1200ms 防抖,仅在停止输入超过阈值后刷新
  183 + onSearchInput(val) {
  184 + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer)
  185 + this.searchDebounceTimer = setTimeout(() => {
  186 + this.searchKeywordDebounced = this.searchKeyword
  187 + this.searchDebounceTimer = null
  188 + }, 1200)
  189 + },
  190 + // uni-search-bar 确认搜索:更新关键字并触发 CardList 刷新
  191 + search(e) {
  192 + const val = e && e.value != null ? e.value : this.searchKeyword
  193 + this.searchKeyword = val
  194 + this.searchKeywordDebounced = val
  195 + },
  196 + onAdd() {
  197 + uni.navigateTo({
  198 + url: '/pages/confirmation_form/add'
  199 + })
  200 + },
  201 + openFilter() {
  202 + this.filterVisible = true
  203 + },
  204 + onFilterReset(payload) {
  205 + this.filterForm = payload
  206 + },
  207 + onFilterConfirm(payload) {
  208 + if ((payload.status === '' || payload.status == null) && this.filterForm.status !== '') {
  209 + payload.status = this.filterForm.status
  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 +
  222 + onSampleTypeChange(e) {
  223 + const raw = e && e.detail && e.detail.value !== undefined ?
  224 + e.detail.value :
  225 + (e && e.value !== undefined ? e.value : '')
  226 + this.filterForm.sampleType = raw
  227 + },
  228 +
  229 + onEnterpriseTypeChange(e) {
  230 + const raw = e && e.detail && e.detail.value !== undefined ?
  231 + e.detail.value :
  232 + (e && e.value !== undefined ? e.value : '')
  233 + this.filterForm.customerType = raw
  234 + },
  235 +
  236 + // 列表接口(真实请求)
  237 + fetchList({
  238 + pageIndex,
  239 + pageSize,
  240 + query,
  241 + extra
  242 + }) {
  243 + const params = {
  244 + pageIndex,
  245 + pageSize,
  246 + ...extra,
  247 + ...query
  248 + }
  249 + if (this.searchKeywordDebounced) {
  250 + params.orderingUnitName = this.searchKeywordDebounced
  251 + }
  252 + return queryApi(params)
  253 + .then(res => {
  254 + const _data = res.data || {};
  255 + const records = _data.datas || [];
  256 + const totalCount = _data.totalCount || 0;
  257 + const hasNext = _data.hasNext || false
  258 + return {
  259 + records,
  260 + totalCount,
  261 + hasNext
  262 + }
  263 + })
  264 + .catch(err => {
  265 + console.error('fetchList error', err)
  266 + this.onCardError()
  267 + return {
  268 + records: [],
  269 + totalCount: 0,
  270 + hasNext: false
  271 + }
  272 + })
  273 + },
  274 + loadAllDicData() {
  275 + const dicCodes = ['AUDIT_STATUS', 'ENTERPRISE_TYPE', 'SAMPLE_TYPE']
  276 + return getDicByCodes(dicCodes).then(results => {
  277 + this.dicOptions.AUDIT_STATUS = results.AUDIT_STATUS.data || []
  278 + this.dicOptions.ENTERPRISE_TYPE = results.ENTERPRISE_TYPE.data || []
  279 + this.dicOptions.SAMPLE_TYPE = results.SAMPLE_TYPE.data || []
  280 + this.statusLocal = (this.dicOptions.AUDIT_STATUS || []).map(it => ({
  281 + value: it.code,
  282 + text: it.name
  283 + }))
  284 + this.enterpriseTypeLocal = (this.dicOptions.ENTERPRISE_TYPE || []).map(it => ({
  285 + value: it.code,
  286 + text: it.name
  287 + }))
  288 + this.sampleTypeLocal = (this.dicOptions.SAMPLE_TYPE || []).map(it => ({
  289 + value: it.code,
  290 + text: it.name
  291 + }))
  292 + }).catch(() => {
  293 + this.dicOptions = {
  294 + AUDIT_STATUS: [],
  295 + ENTERPRISE_TYPE: [], // 客户类型
  296 + SAMPLE_TYPE: [], // 试样种类
  297 + }
  298 + this.statusLocal = []
  299 + this.enterpriseTypeLocal = []
  300 + this.sampleTypeLocal = []
  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/confirmation_form/detail' + query
  309 + })
  310 + },
  311 + onWorkshopChange(e) {
  312 + const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ? e.value : '')
  313 + this.filterForm.workshopId = raw
  314 + const match = (this.workshopOptions || []).find(o => String(o.value) === String(raw))
  315 + this.filterForm.workshopIdName = match ? (match.text || '') : ''
  316 + },
  317 + filterStatus(status) {
  318 + const _item = this.statusLocal.filter(item => item.value === status)[0] || {};
  319 + return _item.text || '';
  320 + },
  321 + }
  322 +}
  323 +</script>
  324 +
  325 +<style lang="scss" scoped>
  326 +.page {
  327 + display: flex;
  328 + flex-direction: column;
  329 + height: 100vh;
  330 +}
  331 +
  332 +.dev-list-fixed {
  333 + position: fixed;
  334 + top: 96rpx;
  335 + left: 0;
  336 + right: 0;
  337 + z-index: 2;
  338 + background: #fff;
  339 +
  340 + .search-row {
  341 + display: flex;
  342 + align-items: center;
  343 + padding: 16rpx 32rpx;
  344 +
  345 + .uni-searchbar {
  346 + padding: 0;
  347 + flex: 1;
  348 + }
  349 +
  350 + .tool-icons {
  351 + display: flex;
  352 +
  353 + .tool-icon {
  354 + width: 48rpx;
  355 + height: 48rpx;
  356 + display: block;
  357 + margin-left: 32rpx;
  358 + }
  359 + }
  360 + }
  361 +
  362 +}
  363 +
  364 +/* 仅当前页覆盖 uni-search-bar 盒子高度 */
  365 +::v-deep .uni-searchbar__box {
  366 + height: 80rpx !important;
  367 + justify-content: start;
  368 +
  369 + .uni-searchbar__box-search-input {
  370 + font-size: 32rpx !important;
  371 + }
  372 +}
  373 +
  374 +.list-box {
  375 + flex: 1;
  376 + padding-top: 140rpx;
  377 +
  378 + &.pad-batch {
  379 + padding-bottom: 144rpx;
  380 + }
  381 +
  382 + .card {
  383 + position: relative;
  384 + }
  385 +
  386 + .card-header {
  387 + margin-bottom: 28rpx;
  388 + position: relative;
  389 +
  390 + .title {
  391 + font-size: 36rpx;
  392 + font-weight: 600;
  393 + line-height: 50rpx;
  394 + color: rgba(0, 0, 0, 0.9);
  395 + width: 578rpx;
  396 + }
  397 +
  398 + .status {
  399 + font-weight: 600;
  400 + position: absolute;
  401 + top: -32rpx;
  402 + right: -12rpx;
  403 + height: 48rpx;
  404 + line-height: 48rpx;
  405 + color: #fff;
  406 + font-size: 24rpx;
  407 + padding: 0 14rpx;
  408 + border-radius: 6rpx;
  409 +
  410 + // 审核中
  411 + &.status_AUDIT {
  412 + background: $theme-primary;
  413 + }
  414 +
  415 + // 审核通过
  416 + &.status_PASS {
  417 + background: #2BA471;
  418 + }
  419 +
  420 + // 已驳回
  421 + &.status_REFUSE {
  422 + background: #d54941;
  423 + }
  424 +
  425 + // 已取消
  426 + &.status_CANCEL {
  427 + background: #e7e7e7;
  428 + color: rgba(0, 0, 0, 0.6);
  429 + }
  430 +
  431 + }
  432 +
  433 + }
  434 +
  435 + .info-row {
  436 + display: flex;
  437 + align-items: center;
  438 + color: rgba(0, 0, 0, 0.6);
  439 + font-size: 28rpx;
  440 + margin-bottom: 24rpx;
  441 +
  442 + &:last-child {
  443 + margin-bottom: 0;
  444 + }
  445 +
  446 + text {
  447 + width: 60%;
  448 + line-height: 32rpx;
  449 +
  450 + &:last-child {
  451 + color: rgba(0, 0, 0, 0.9);
  452 + width: 40%;
  453 + }
  454 +
  455 + &.category {
  456 + display: inline-block;
  457 + padding: 4rpx 12rpx;
  458 + border-radius: 6rpx;
  459 + font-size: 24rpx;
  460 + width: auto;
  461 +
  462 + &.category_A {
  463 + background: #FFF0ED;
  464 + color: #D54941;
  465 + }
  466 +
  467 + &.category_B {
  468 + background: #FFF1E9;
  469 + color: #E37318;
  470 + }
  471 +
  472 + &.category_C {
  473 + background: #F2F3FF;
  474 + color: $theme-primary;
  475 + }
  476 +
  477 + &.category_D {
  478 + background: #E3F9E9;
  479 + color: #2BA471;
  480 + }
  481 + }
  482 + }
  483 +
  484 + }
  485 +}
  486 +
  487 +.filter-form {
  488 + .form-item {
  489 + margin-bottom: 24rpx;
  490 + }
  491 +
  492 + .label {
  493 + margin-bottom: 20rpx;
  494 + color: rgba(0, 0, 0, 0.9);
  495 + height: 44rpx;
  496 + line-height: 44rpx;
  497 + font-size: 30rpx;
  498 + }
  499 +
  500 + .uni-easyinput {
  501 + border: 1rpx solid #f3f3f3;
  502 + }
  503 +
  504 +}
  505 +
  506 +/* 深度覆盖 uni-data-checkbox(mode=tag)内部的 tag 展示与间距 */
  507 +::v-deep .filter-form .uni-data-checklist .checklist-group {
  508 + .checklist-box {
  509 + &.is--tag {
  510 + width: 212rpx;
  511 + margin-top: 0;
  512 + margin-bottom: 24rpx;
  513 + margin-right: 24rpx;
  514 + height: 80rpx;
  515 + padding: 0 20rpx;
  516 + border-radius: 12rpx;
  517 + background-color: #f3f3f3;
  518 + border-color: #f3f3f3;
  519 +
  520 + &:nth-child(3n) {
  521 + margin-right: 0;
  522 + }
  523 +
  524 + .checklist-content {
  525 + display: flex;
  526 + justify-content: center;
  527 + }
  528 +
  529 + .checklist-text {
  530 + color: rgba(0, 0, 0, 0.9);
  531 + font-size: 28rpx;
  532 + text-align: center;
  533 + }
  534 + }
  535 +
  536 + &.is-checked {
  537 + background-color: $theme-primary-plain-bg !important;
  538 + border-color: $theme-primary-plain-bg !important;
  539 +
  540 + .checklist-text {
  541 + color: $theme-primary !important;
  542 + }
  543 + }
  544 + }
  545 +
  546 +}
  547 +</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.orderingUnitName }}</view>
  9 + </template>
  10 + </uni-list-item>
  11 + <uni-list-item class="select-item" :class="form.sampleTypeName ? 'is-filled' : 'is-empty'" clickable
  12 + @click="openSheet('sampleType')" :rightText="form.sampleTypeName || '请选择'" showArrow>
  13 + <template v-slot:body>
  14 + <view class="item-title"><text>试样种类</text></view>
  15 + </template>
  16 + </uni-list-item>
  17 + <uni-list-item class="select-item" :class="form.customerTypeName ? 'is-filled' : 'is-empty'" clickable
  18 + @click="openSheet('customerType')" :rightText="form.customerTypeName || '请选择'" showArrow>
  19 + <template v-slot:body>
  20 + <view class="item-title"><text>客户类型</text></view>
  21 + </template>
  22 + </uni-list-item>
  23 + <uni-list-item title="生产厂">
  24 + <template v-slot:footer>
  25 + <view class="readonly-text">{{ form.workshopName }}</view>
  26 + </template>
  27 + </uni-list-item>
  28 + <uni-list-item title="所属品种">
  29 + <template v-slot:footer>
  30 + <view class="readonly-text">{{ form.belongingBreed }}</view>
  31 + </template>
  32 + </uni-list-item>
  33 + <uni-list-item title="原供货同行">
  34 + <template v-slot:footer>
  35 + <uni-easyinput v-model="form.originalSupplierPeer" placeholder="请输入原供货同行" :inputBorder="false" />
  36 + </template>
  37 + </uni-list-item>
  38 + </view>
  39 +
  40 + <!-- 产品 -->
  41 + <view class="section2">
  42 + <!-- mode="add" 允许编辑 -->
  43 + <Product mode="add" :list="initPurchaseOrderLineList" @change="purchaseOrderLineListChange"
  44 + :provideSamplesOptions="provideSamplesOptions" :clearParametersOptions="clearParametersOptions" />
  45 + </view>
  46 +
  47 + <view class="section">
  48 +
  49 + <uni-list-item class="select-item" :class="form.sampleQuantityRegulationName ? 'is-filled' : 'is-empty'" clickable
  50 + @click="openSheet('sampleQuantityRegulation')" :rightText="form.sampleQuantityRegulationName || '请选择'" showArrow>
  51 + <template v-slot:body>
  52 + <view class="item-title"><text>本次试样数量是否超规定</text></view>
  53 + </template>
  54 + </uni-list-item>
  55 +
  56 + <uni-list-item class="select-item" :class="form.specificationQuantityRegulationName ? 'is-filled' : 'is-empty'" clickable
  57 + @click="openSheet('specificationQuantityRegulation')" :rightText="form.specificationQuantityRegulationName || '请选择'" showArrow>
  58 + <template v-slot:body>
  59 + <view class="item-title"><text>试样规格个数是否超规定</text></view>
  60 + </template>
  61 + </uni-list-item>
  62 +
  63 + <uni-list-item title="试样次数">
  64 + <template v-slot:footer>
  65 + <uni-easyinput type="textarea" v-model="form.sampleFrequency" placeholder="请输入试样次数" :inputBorder="false" />
  66 + </template>
  67 + </uni-list-item>
  68 +
  69 + <uni-list-item title="前期不合格描述">
  70 + <template v-slot:footer>
  71 + <uni-easyinput type="textarea" v-model="form.earlyNonconformityDescription" placeholder="请输入前期不合格描述" :inputBorder="false" />
  72 + </template>
  73 + </uni-list-item>
  74 +
  75 + </view>
  76 +
  77 + <view class="footer">
  78 + <view class="view-total">
  79 + <view class="head">合计</view>
  80 + <view class="row">
  81 + <view class="row2">
  82 + <text class="label">数量</text><text class="value">{{ form.totalQuantity }}</text>
  83 + </view>
  84 + </view>
  85 + </view>
  86 + <button class="btn submit" type="primary" @click="onSubmit">保存</button>
  87 + </view>
  88 + </uni-list>
  89 + </scroll-view>
  90 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
  91 + @confirm="onSheetConfirm" />
  92 + </view>
  93 +</template>
  94 +
  95 +<script>
  96 +import { updateApi, getDetailApi } from '@/api/confirmation_form.js'
  97 +import Product from './product.vue'
  98 +import SingleSelectSheet from '@/components/single-select/index.vue'
  99 +import {
  100 + getDicByCodes
  101 +} from '@/utils/dic'
  102 +
  103 +export default {
  104 + name: 'ConfirmationFormModify',
  105 + components: { Product, SingleSelectSheet },
  106 + data() {
  107 + return {
  108 + form: {
  109 + purchaseOrderId: '',
  110 + id: '',
  111 + // 订单基础信息
  112 + purchaseOrderName: '',
  113 + customerName: '',
  114 + customerId: '',
  115 + workshopName: '',
  116 + workshopId: '',
  117 + originPlanShipDate: '',
  118 + deptName: '',
  119 + deptId: '',
  120 + totalQuantity: '',
  121 + totalShippedQuantity: '',
  122 + totalSupplementaryQuantity: '',
  123 + code: '',
  124 + // 默认当前日期 格式为 yyyy-MM-dd
  125 + orderDate: new Date().toISOString().substring(0, 10),
  126 +
  127 + },
  128 + initPurchaseOrderLineList: [],
  129 + maxDeliveryDate: new Date().toISOString().substring(0, 10),
  130 + sheet: { visible: false, title: '请选择', options: [], value: '', field: '' },
  131 + dicOptions: {
  132 + ENTERPRISE_TYPE: [], // 客户类型
  133 + SAMPLE_TYPE: [], // 试样种类
  134 + CLEAR_PARAMETERS: [], // 是否提供明确参数
  135 + PROVIDE_SAMPLES: [], // 是否提供样品
  136 + },
  137 + enterpriseTypeLocal: [], // 客户类型
  138 + sampleTypeLocal: [], // 试样种类
  139 + provideSamplesOptions: [], // 是否提供样品
  140 + clearParametersOptions: [], // 是否提供明确参数
  141 + }
  142 + },
  143 + onLoad(query) {
  144 + const id = (query && (query.id || query.code)) || ''
  145 + if (id) {
  146 + this.loadDetail(id)
  147 + this.loadAllDicData()
  148 + }
  149 + },
  150 + methods: {
  151 + async loadDetail(id) {
  152 + try {
  153 + const res = await getDetailApi(id)
  154 + const m = res.data || {}
  155 + const next = { ...this.form, ...m }
  156 + // 确保ID存在
  157 + next.id = m.id || id
  158 + next.sampleQuantityRegulationName = m.sampleQuantityRegulation === true ? '是' : '否'
  159 + next.specificationQuantityRegulationName = m.specificationQuantityRegulation === true ? '是' : '否'
  160 + // 映射列表
  161 + // 注意:详情返回的是 productSampleConfirmationSlipDetailList,需要赋值给 initPurchaseOrderLineList 以便 Product 组件初始化
  162 + // 且需要处理字段兼容性,确保 Product 组件能正确显示和编辑
  163 + const lines = Array.isArray(m.productSampleConfirmationSlipDetailList) ? m.productSampleConfirmationSlipDetailList.map(x => ({
  164 + ...x,
  165 + // 确保 Product 组件需要的字段存在
  166 + // Product组件使用: quantity(需发), shippedQuantity(实发), supplementaryQuantity(需求补货), salesPrice(单价)
  167 + // 详情接口返回的字段应该已经包含了这些,如果有差异需要在此处转换
  168 + // 注意:add.vue中 onRelateConfirm 做了映射,这里是回显,通常直接使用即可
  169 + })) : []
  170 +
  171 + this.form = next;
  172 + this.initPurchaseOrderLineList = lines;
  173 + } catch (e) {
  174 + uni.showToast({ title: '加载失败', icon: 'none' })
  175 + }
  176 + },
  177 + loadAllDicData() {
  178 + const dicCodes = ['ENTERPRISE_TYPE', 'SAMPLE_TYPE', 'CLEAR_PARAMETERS', 'PROVIDE_SAMPLES']
  179 + return getDicByCodes(dicCodes).then(results => {
  180 + this.dicOptions.ENTERPRISE_TYPE = results.ENTERPRISE_TYPE.data || []
  181 + this.dicOptions.SAMPLE_TYPE = results.SAMPLE_TYPE.data || []
  182 + this.dicOptions.CLEAR_PARAMETERS = results.CLEAR_PARAMETERS.data || []
  183 + this.dicOptions.PROVIDE_SAMPLES = results.PROVIDE_SAMPLES.data || []
  184 +
  185 + this.enterpriseTypeLocal = (this.dicOptions.ENTERPRISE_TYPE || []).map(it => ({
  186 + value: it.code,
  187 + label: it.name
  188 + }))
  189 + this.sampleTypeLocal = (this.dicOptions.SAMPLE_TYPE || []).map(it => ({
  190 + value: it.code,
  191 + label: it.name
  192 + }))
  193 + this.provideSamplesOptions = (this.dicOptions.PROVIDE_SAMPLES || []).map(it => ({
  194 + value: it.code,
  195 + label: it.name
  196 + }))
  197 + this.clearParametersOptions = (this.dicOptions.CLEAR_PARAMETERS || []).map(it => ({
  198 + value: it.code,
  199 + label: it.name
  200 + }))
  201 + }).catch(() => {
  202 + this.dicOptions = {
  203 + ENTERPRISE_TYPE: [], // 客户类型
  204 + SAMPLE_TYPE: [], // 试样种类
  205 + CLEAR_PARAMETERS: [], // 是否提供明确参数
  206 + PROVIDE_SAMPLES: [], // 是否提供样品
  207 + }
  208 + this.enterpriseTypeLocal = []
  209 + this.sampleTypeLocal = []
  210 + this.provideSamplesOptions = []
  211 + this.clearParametersOptions = []
  212 + })
  213 + },
  214 + validateRequired() {
  215 + // const checks = [
  216 + // { key: 'purchaseOrderName', label: '订单编号' }
  217 + // ]
  218 + // for (const it of checks) {
  219 + // const val = this.form[it.key]
  220 + // if (val === undefined || val === null || String(val).trim() === '') {
  221 + // uni.showToast({ title: `请先选择${it.label}`, icon: 'none' })
  222 + // return false
  223 + // }
  224 + // }
  225 + return true
  226 + },
  227 + validateLineListRequired() {
  228 + const list = Array.isArray(this.form.purchaseOrderLineList) ? this.form.purchaseOrderLineList : []
  229 + if (list.length === 0) {
  230 + uni.showToast({ title: '请先添加产品', icon: 'none' })
  231 + return false
  232 + }
  233 + const fields = [
  234 + { key: 'brand', label: '牌号' },
  235 + { key: 'quantity', label: '需发' },
  236 + { key: 'supplementaryQuantity', label: '需求补货' },
  237 + ]
  238 + for (let i = 0; i < list.length; i++) {
  239 + const it = list[i] || {}
  240 + for (const f of fields) {
  241 + const v = it && it[f.key]
  242 + if (v === undefined || v === null || String(v).trim() === '') {
  243 + uni.showToast({ title: `产品第${i + 1}条:${f.label}不能为空!`, icon: 'none' })
  244 + return false
  245 + }
  246 + }
  247 + const has = (v) => v !== undefined && v !== null && String(v).trim() !== ''
  248 + if (has(it.thicknessTolPos) && has(it.thicknessTolNeg)) {
  249 + const pos = Number(it.thicknessTolPos)
  250 + const neg = Number(it.thicknessTolNeg)
  251 + if (!(pos > neg)) {
  252 + uni.showToast({ title: `产品第${i + 1}条:厚度公差上限需大于下限`, icon: 'none' })
  253 + return false
  254 + }
  255 + }
  256 + if (has(it.widthTolPos) && has(it.widthTolNeg)) {
  257 + const pos = Number(it.widthTolPos)
  258 + const neg = Number(it.widthTolNeg)
  259 + if (!(pos > neg)) {
  260 + uni.showToast({ title: `产品第${i + 1}条:宽度公差上限需大于下限`, icon: 'none' })
  261 + return false
  262 + }
  263 + }
  264 + if (has(it.lengthTolPos) && has(it.lengthTolNeg)) {
  265 + const pos = Number(it.lengthTolPos)
  266 + const neg = Number(it.lengthTolNeg)
  267 + if (!(pos > neg)) {
  268 + uni.showToast({ title: `产品第${i + 1}条:长度公差上限需大于下限`, icon: 'none' })
  269 + return false
  270 + }
  271 + }
  272 + }
  273 + return true
  274 + },
  275 + async onSubmit() {
  276 + if (!this.validateRequired()) return
  277 + const payload = { ...this.form }
  278 + delete payload.status
  279 + console.log('onSubmit__payload', payload)
  280 +
  281 + try {
  282 + await updateApi(payload)
  283 + uni.showToast({ title: '保存成功', icon: 'success' })
  284 + setTimeout(() => { uni.redirectTo({ url: '/pages/confirmation_form/index' }) }, 300)
  285 + } catch (e) {
  286 + uni.showToast({ title: (e && e.msg) || '保存失败', icon: 'none' })
  287 + }
  288 + },
  289 + calculateSummary(list) {
  290 + const summary = (list || []).reduce((acc, it) => {
  291 + const qty = Number(it.supplementaryQuantity) || 0
  292 + const shipped = Number(it.shippedQuantity) || 0
  293 + const orderQty = Number(it.quantity) || 0
  294 + acc.totalSupplementaryQuantity += qty
  295 + acc.totalShippedQuantity += shipped
  296 + acc.totalQuantity += orderQty
  297 + return acc
  298 + }, { totalQuantity: 0, totalShippedQuantity: 0, totalSupplementaryQuantity: 0 })
  299 +
  300 + const fixedTotalQuantity = Number(summary.totalQuantity.toFixed(2))
  301 + const fixedTotalShippedQuantity = Number(summary.totalShippedQuantity.toFixed(2))
  302 + const fixedTotalSupplementaryQuantity = Number(summary.totalSupplementaryQuantity.toFixed(2))
  303 + this.form.totalQuantity = fixedTotalQuantity
  304 + this.form.totalShippedQuantity = fixedTotalShippedQuantity
  305 + this.form.totalSupplementaryQuantity = fixedTotalSupplementaryQuantity
  306 + },
  307 + purchaseOrderLineListChange(data) {
  308 + const list = Array.isArray(data) ? data : []
  309 + this.form.productSampleConfirmationSlipDetailList = list
  310 + },
  311 + openSheet(field) {
  312 + let options = []
  313 + let title = ''
  314 + let value = ''
  315 +
  316 + if (field === 'sampleType') {
  317 + title = '试样种类'
  318 + options = this.sampleTypeLocal
  319 + value = this.form.sampleType
  320 + } else if (field === 'customerType') {
  321 + title = '客户类型'
  322 + options = this.enterpriseTypeLocal
  323 + value = this.form.customerType
  324 + } else if (field === 'sampleQuantityRegulation') {
  325 + title = '本次试样数量是否超规定'
  326 + options = [{ value: true, label: '是' }, { value: false, label: '否' }]
  327 + value = this.form.sampleQuantityRegulation
  328 + } else if (field === 'specificationQuantityRegulation') {
  329 + title = '试样规格个数是否超规定'
  330 + options = [{ value: true, label: '是' }, { value: false, label: '否' }]
  331 + value = this.form.specificationQuantityRegulation
  332 + }
  333 +
  334 + const match = options.find(o => String(o.value) === String(value))
  335 + this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
  336 + },
  337 + onSheetConfirm({ value, label }) {
  338 + const field = this.sheet.field
  339 + this.form[field] = value
  340 + this.form[field + 'Name'] = label
  341 + this.sheet.visible = false
  342 + },
  343 + }
  344 +}
  345 +</script>
  346 +
  347 +<style lang="scss" scoped>
  348 +.page {
  349 + display: flex;
  350 + flex-direction: column;
  351 + height: 100%;
  352 +}
  353 +
  354 +.scroll {
  355 + flex: 1;
  356 + padding: 6rpx 0 400rpx;
  357 +}
  358 +
  359 +
  360 +
  361 +.title-header {
  362 + background-color: #fff;
  363 + display: flex;
  364 + align-items: center;
  365 + padding: 32rpx 32rpx 22rpx;
  366 +
  367 + .title-header_icon {
  368 + width: 32rpx;
  369 + height: 28rpx;
  370 + margin-right: 16rpx;
  371 + }
  372 +
  373 + span {
  374 + color: rgba(0, 0, 0, 0.9);
  375 + font-size: 32rpx;
  376 + line-height: 44rpx;
  377 + font-weight: 600;
  378 + }
  379 +}
  380 +
  381 +
  382 +.section {
  383 + background: #fff;
  384 + margin-bottom: 20rpx;
  385 +}
  386 +
  387 +.section2 {
  388 + background: #f1f1f1;
  389 +}
  390 +
  391 +::v-deep .uni-list {
  392 + background: transparent;
  393 +
  394 + &-item {
  395 + &__extra-text {
  396 + font-size: 32rpx;
  397 + }
  398 +
  399 + &__content-title {
  400 + font-size: 32rpx;
  401 + color: rgba(0, 0, 0, 0.9);
  402 + }
  403 +
  404 + &__container {
  405 + padding: 32rpx;
  406 + // align-items: center;
  407 +
  408 + .uni-easyinput {
  409 +
  410 + .is-disabled {
  411 + background-color: transparent !important;
  412 + }
  413 +
  414 + &__placeholder-class {
  415 + font-size: 32rpx;
  416 + color: rgba(0, 0, 0, 0.4);
  417 + }
  418 +
  419 + &__content {
  420 + border: none;
  421 +
  422 + &-input {
  423 + padding-left: 0 !important;
  424 + height: 48rpx;
  425 + line-height: 48rpx;
  426 + font-size: 32rpx;
  427 + }
  428 +
  429 + .content-clear-icon {
  430 + font-size: 44rpx !important;
  431 + }
  432 + }
  433 + }
  434 +
  435 + .amount-row {
  436 + flex: 1;
  437 + display: flex;
  438 + align-items: center;
  439 +
  440 + .uni-easyinput {
  441 + flex: 1;
  442 + }
  443 +
  444 + .unit {
  445 + margin-left: 16rpx;
  446 + color: rgba(0, 0, 0, 0.9);
  447 + }
  448 + }
  449 +
  450 + .item-title,
  451 + .uni-list-item__content {
  452 + flex: none;
  453 + min-height: 48rpx;
  454 + line-height: 48rpx;
  455 + font-size: 32rpx;
  456 + position: relative;
  457 + width: 210rpx;
  458 + margin-right: 32rpx;
  459 + color: rgba(0, 0, 0, 0.9);
  460 + padding-right: 0;
  461 +
  462 +
  463 + .required {
  464 + color: red;
  465 + position: absolute;
  466 + top: 50%;
  467 + transform: translateY(-50%);
  468 + left: -16rpx;
  469 + }
  470 + }
  471 +
  472 + }
  473 +
  474 + &.select-item {
  475 + &.is-empty {
  476 + .uni-list-item__extra-text {
  477 + color: rgba(0, 0, 0, 0.4) !important;
  478 + }
  479 + }
  480 +
  481 + &.is-filled {
  482 + .uni-list-item__extra-text {
  483 + color: rgba(0, 0, 0, 0.9) !important;
  484 + }
  485 + }
  486 +
  487 + .serial-number-row {
  488 + display: flex;
  489 + align-items: center;
  490 + }
  491 +
  492 + }
  493 +
  494 + &.mgb10 {
  495 + margin-bottom: 20rpx;
  496 + }
  497 +
  498 + }
  499 +
  500 + .title-header {
  501 + background-color: #fff;
  502 + display: flex;
  503 + align-items: center;
  504 + padding: 32rpx 32rpx 22rpx;
  505 +
  506 + &_icon {
  507 + width: 32rpx;
  508 + height: 28rpx;
  509 + margin-right: 16rpx;
  510 + }
  511 +
  512 + span {
  513 + color: rgba(0, 0, 0, 0.9);
  514 + font-size: 32rpx;
  515 + line-height: 44rpx;
  516 + font-weight: 600;
  517 + }
  518 + }
  519 +}
  520 +
  521 +/* 只读 easyinput 根据内容自适应高度 */
  522 +::v-deep .uni-list-item__container {
  523 + align-items: flex-start;
  524 +}
  525 +
  526 +/* 只读文本样式 */
  527 +.readonly-text {
  528 + color: rgba(0, 0, 0, 0.9);
  529 + font-size: 32rpx;
  530 + line-height: 48rpx;
  531 + text-align: right;
  532 + white-space: pre-wrap;
  533 + word-break: break-all;
  534 +}
  535 +
  536 +
  537 +.footer {
  538 + position: fixed;
  539 + left: 0;
  540 + right: 0;
  541 + bottom: 0;
  542 + padding: 0 32rpx 32rpx;
  543 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  544 + background: #fff;
  545 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  546 + z-index: 10;
  547 +
  548 + .btn {
  549 + height: 80rpx;
  550 + line-height: 80rpx;
  551 + border-radius: 12rpx;
  552 + font-size: 32rpx;
  553 + }
  554 +
  555 + .submit {
  556 + background: $theme-primary;
  557 + color: #fff;
  558 + }
  559 +
  560 + .view-total {
  561 + padding: 20rpx 0;
  562 +
  563 + .head {
  564 + font-size: 32rpx;
  565 + font-weight: 600;
  566 + line-height: 50rpx;
  567 + color: rgba(0, 0, 0, 0.9);
  568 + padding-bottom: 16rpx;
  569 + margin-bottom: 24rpx;
  570 + border-bottom: 1px dashed #E7E7E7;
  571 + }
  572 +
  573 + .row {
  574 + display: flex;
  575 + margin-bottom: 24rpx;
  576 + line-height: 32rpx;
  577 +
  578 + .row2 {
  579 + width: 50%;
  580 + }
  581 +
  582 + .label {
  583 + width: 180rpx;
  584 + margin-right: 14rpx;
  585 + color: rgba(0, 0, 0, 0.6);
  586 + font-size: 32rpx;
  587 + }
  588 +
  589 + .value {
  590 + flex: 1;
  591 + color: rgba(0, 0, 0, 0.9);
  592 + font-size: 32rpx;
  593 + white-space: pre-wrap;
  594 + word-break: break-all;
  595 + font-weight: 600;
  596 + }
  597 + }
  598 + }
  599 +}
  600 +</style>
  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 + <view class="row"><text class="label">牌号</text><text class="value">{{ item.brand }}</text></view>
  21 + <!-- 厚(公差) * 宽(公差) * 长(公差) -->
  22 + <view class="row row-spec"><text class="label">规格(mm)</text>
  23 + <view class="value value-spec">
  24 + <view v-if="item.thickness" class="value-spec_val">{{ item.thickness }}</view>
  25 + <view v-if="item.thickness" class="value-spec_box">
  26 + <view v-if="item.thicknessTolPos" class="value-spec_box_1">{{ item.thicknessTolPos > 0 ? '+' + item.thicknessTolPos : item.thicknessTolPos }}
  27 + </view>
  28 + <view v-if="item.thicknessTolNeg" class="value-spec_box_2">{{ item.thicknessTolNeg > 0 ? '+' + item.thicknessTolNeg : item.thicknessTolNeg }}
  29 + </view>
  30 + </view>
  31 + <view v-if="item.width" class="value-spec_val p12">*</view>
  32 + <view v-if="item.width" class="value-spec_val">{{ item.width }}</view>
  33 + <view v-if="item.width" class="value-spec_box">
  34 + <view v-if="item.widthTolPos" class="value-spec_box_1">{{ item.widthTolPos > 0 ? '+' +
  35 + item.widthTolPos : item.widthTolPos }}</view>
  36 + <view v-if="item.widthTolNeg" class="value-spec_box_2">{{ item.widthTolNeg > 0 ? '+' +
  37 + item.widthTolNeg : item.widthTolNeg }}</view>
  38 + </view>
  39 + <view v-if="item.length" class="value-spec_val p12">*</view>
  40 + <view v-if="item.length" class="value-spec_val">{{ item.length }}</view>
  41 + <view v-if="item.length" class="value-spec_box">
  42 + <view v-if="item.lengthTolPos" class="value-spec_box_1">{{ item.lengthTolPos > 0 ? '+' +
  43 + item.lengthTolPos : item.lengthTolPos }}</view>
  44 + <view v-if="item.lengthTolNeg" class="value-spec_box_2">{{ item.lengthTolNeg > 0 ? '+' +
  45 + item.lengthTolNeg : item.lengthTolNeg }}</view>
  46 + </view>
  47 + </view>
  48 + </view>
  49 + <view class="row"><text class="label">状态</text><text class="value">{{ item.status }}</text></view>
  50 + <view v-show="!item.collapsed">
  51 +
  52 + <view class="row" :class="{ 'noneStyle': !item.showSalesPrice }"><text
  53 + class="label">数量kg</text><text class="value">{{ item.quantity }}</text>
  54 + </view>
  55 +
  56 + <uni-list class="edit-list">
  57 + <uni-list-item class="select-item"
  58 + :class="item.provideSamplesName ? 'is-filled' : 'is-empty'" clickable
  59 + @click="openProductSheet(idx, 'provideSamples')"
  60 + :rightText="item.provideSamplesName || '请选择是否提供样品'" showArrow>
  61 + <template v-slot:body>
  62 + <view class="item-title"><text>是否提供样品</text></view>
  63 + </template>
  64 + </uni-list-item>
  65 + <uni-list-item class="select-item"
  66 + :class="item.clearParametersName ? 'is-filled' : 'is-empty'" clickable
  67 + @click="openProductSheet(idx, 'clearParameters')"
  68 + :rightText="item.clearParametersName || '请选择是否提供明确参数'" showArrow>
  69 + <template v-slot:body>
  70 + <view class="item-title"><text>是否提供明确参数</text></view>
  71 + </template>
  72 + </uni-list-item>
  73 + </uni-list>
  74 + </view>
  75 +
  76 + <view class="block-ops">
  77 + <div class="toggle" @click="toggleItem(idx)">
  78 + <image :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'"
  79 + class="icon" />
  80 + {{ item.collapsed ? '展开' : '收起' }}
  81 + </div>
  82 + </view>
  83 + </view>
  84 + </view>
  85 +
  86 + <view v-else-if="mode === 'view'" class="view-list" v-show="!collapsedView">
  87 + <view v-for="(item, idx) in items" :key="'v-' + idx" class="card">
  88 + <view class="row"><text class="label">牌号</text><text class="value">{{ item.brand }}</text></view>
  89 + <!-- 厚(公差) * 宽(公差) * 长(公差) -->
  90 + <view class="row row-spec"><text class="label">规格(mm)</text>
  91 + <view class="value value-spec">
  92 + <view v-if="item.thickness" class="value-spec_val">{{ item.thickness }}</view>
  93 + <view v-if="item.thickness" class="value-spec_box">
  94 + <view v-if="item.thicknessTolPos" class="value-spec_box_1">{{ item.thicknessTolPos > 0 ? '+'
  95 + +
  96 + item.thicknessTolPos : item.thicknessTolPos }}
  97 + </view>
  98 + <view v-if="item.thicknessTolNeg" class="value-spec_box_2">{{ item.thicknessTolNeg > 0 ? '+'
  99 + +
  100 + item.thicknessTolNeg : item.thicknessTolNeg }}
  101 + </view>
  102 + </view>
  103 + <view v-if="item.width" class="value-spec_val p12">*</view>
  104 + <view v-if="item.width" class="value-spec_val">{{ item.width }}</view>
  105 + <view v-if="item.width" class="value-spec_box">
  106 + <view v-if="item.widthTolPos" class="value-spec_box_1">{{ item.widthTolPos > 0 ? '+' +
  107 + item.widthTolPos : item.widthTolPos }}
  108 + </view>
  109 + <view v-if="item.widthTolNeg" class="value-spec_box_2">{{ item.widthTolNeg > 0 ? '+' +
  110 + item.widthTolNeg : item.widthTolNeg }}
  111 + </view>
  112 + </view>
  113 + <view v-if="item.length" class="value-spec_val p12">*</view>
  114 + <view v-if="item.length" class="value-spec_val">{{ item.length }}</view>
  115 + <view v-if="item.length" class="value-spec_box">
  116 + <view v-if="item.lengthTolPos" class="value-spec_box_1">{{ item.lengthTolPos > 0 ? '+' +
  117 + item.lengthTolPos : item.lengthTolPos }}
  118 + </view>
  119 + <view v-if="item.lengthTolNeg" class="value-spec_box_2">{{ item.lengthTolNeg > 0 ? '+' +
  120 + item.lengthTolNeg : item.lengthTolNeg }}
  121 + </view>
  122 + </view>
  123 + </view>
  124 + </view>
  125 + <view class="row"><text class="label">状态</text><text class="value">{{ item.status }}</text></view>
  126 + <view class="row"><text class="label">数量(kg)</text><text class="value">{{ item.quantity }}</text>
  127 + </view>
  128 + <view class="row"><text class="label">是否提供样品</text><text class="value">{{ item.provideSamplesName
  129 + }}</text>
  130 + </view>
  131 + <view class="row"><text class="label">是否提供明确参数</text><text class="value">{{ item.clearParametersName
  132 + }}</text>
  133 + </view>
  134 + </view>
  135 + </view>
  136 +
  137 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" />
  138 + </view>
  139 +</template>
  140 +<script>
  141 +import { uuid } from '@/utils/uuid.js'
  142 +import SingleSelectSheet from '@/components/single-select/index.vue'
  143 +export default {
  144 + name: 'Product',
  145 + props: {
  146 + title: { type: String, default: '' },
  147 + mode: { type: String, default: 'add' },
  148 + list: { type: Array, default: () => [] },
  149 + max: { type: Number, default: 8 },
  150 + provideSamplesOptions: { type: Array, default: () => [] },
  151 + clearParametersOptions: { type: Array, default: () => [] },
  152 + },
  153 + components: { SingleSelectSheet },
  154 + data() {
  155 + return {
  156 + items: [],
  157 + collapsedView: false,
  158 + roleCodes: [],
  159 + sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1, mode: '' }
  160 + }
  161 + },
  162 + computed: {
  163 + minDeliveryDate() {
  164 + const s = this.orderDate
  165 + if (!s) return ''
  166 + const parts = String(s).split('-')
  167 + const y = Number(parts[0])
  168 + const m = Number(parts[1])
  169 + const d = Number(parts[2])
  170 + if (!y || !m || !d) return ''
  171 + const dt = new Date(y, m - 1, d)
  172 + dt.setDate(dt.getDate() + 1)
  173 + const yy = dt.getFullYear()
  174 + const mm = String(dt.getMonth() + 1).padStart(2, '0')
  175 + const dd = String(dt.getDate()).padStart(2, '0')
  176 + return `${yy}/${mm}/${dd}`
  177 + },
  178 + // roleCodes() {
  179 + // const g = this.$store && this.$store.getters
  180 + // return (g && g.roleCodes) || [];
  181 + // },
  182 + },
  183 + watch: {
  184 + items: {
  185 + handler() { this.emitChange() },
  186 + deep: true
  187 + },
  188 + list: {
  189 + handler(v) {
  190 + const arr = Array.isArray(v) ? v : []
  191 + this.items = arr.map(x => {
  192 + const it = { ...this.defaultItem(), ...x, collapsed: true }
  193 + return it
  194 + })
  195 + },
  196 + deep: true
  197 + },
  198 + },
  199 + created() {
  200 + const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, collapsed: false })) : [{ ...this.defaultItem(), collapsed: false }]
  201 + this.items = init;
  202 + },
  203 + methods: {
  204 + defaultItem() {
  205 + return {
  206 + purchaseOrderId: uuid(),
  207 + collapsed: false,
  208 + id: '',
  209 + // 厚度公差
  210 + thicknessTolPos: '',
  211 + thicknessTolNeg: '',
  212 + // 宽度公差
  213 + widthTolPos: '',
  214 + widthTolNeg: '',
  215 + // 长度公差
  216 + lengthTolPos: '',
  217 + lengthTolNeg: '',
  218 + // 其他字段
  219 + industry: '',
  220 + quality: '',
  221 + brand: '',
  222 + thickness: '',
  223 + width: '',
  224 + length: '',
  225 + status: '',
  226 + quantity: '',
  227 + shippedQuantity: '',
  228 + supplementaryQuantity: '',
  229 + confirmedDeliveryDate: '',
  230 + remarks: '',
  231 + }
  232 + },
  233 +
  234 + onAdd() {
  235 + const obj = this.defaultItem()
  236 + obj.collapsed = true
  237 + this.items.push(obj)
  238 + this.emitChange()
  239 + },
  240 + onRemove(id) {
  241 + if (!id) return
  242 + uni.showModal({
  243 + title: '系统提示',
  244 + content: '是否确定删除选中的产品?',
  245 + confirmText: '确定',
  246 + cancelText: '取消',
  247 + success: (res) => {
  248 + if (res && res.confirm) {
  249 + const i = this.items.findIndex(it => String(it.purchaseOrderId) === String(id))
  250 + if (i >= 0) {
  251 + this.items.splice(i, 1)
  252 + this.emitChange()
  253 + }
  254 + }
  255 + }
  256 + })
  257 + },
  258 + toggleItem(idx) {
  259 + const it = this.items[idx]
  260 + if (!it) return
  261 + it.collapsed = !it.collapsed
  262 + this.$set(this.items, idx, it)
  263 + },
  264 + emitChange() {
  265 + const out = this.items.map(it => ({ ...it }))
  266 + this.$emit('input', out)
  267 + this.$emit('update:value', out)
  268 + this.$emit('change', out)
  269 + },
  270 + onNonNegativeNumberInput(val, item, idx, field) {
  271 + let v = String(val != null ? val : (item && item[field]) || '')
  272 + v = v.replace(/[^0-9.]/g, '')
  273 + v = v.replace(/(\..*)\./g, '$1')
  274 + if (v.startsWith('.')) v = '0' + v
  275 + if (v === '') { item[field] = ''; if (typeof idx === 'number') this.$set(this.items, idx, { ...item }); return }
  276 + const num = Number(v)
  277 + if (isNaN(num) || num < 0) {
  278 + item[field] = '0'
  279 + } else {
  280 + item[field] = v
  281 + }
  282 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  283 + },
  284 + onNonNegativeNumberBlur(item, idx, field) {
  285 + const v = String((item && item[field]) || '')
  286 + const num = Number(v)
  287 + if (isNaN(num) || num < 0) item[field] = '0'
  288 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  289 + },
  290 + onRealNumberInput(val, item, idx, field) {
  291 + let s = String(val != null ? val : (item && item[field]) || '')
  292 + const neg = s.trim().startsWith('-')
  293 + s = s.replace(/[^0-9.\-]/g, '')
  294 + s = s.replace(/(?!^)-/g, '')
  295 + s = s.replace(/(\..*)\./g, '$1')
  296 + if (s.startsWith('.')) s = '0' + s
  297 + if (s.startsWith('-.')) s = '-0.' + s.slice(2)
  298 + if (neg && !s.startsWith('-')) s = '-' + s.replace(/-/g, '')
  299 + item[field] = s
  300 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  301 + },
  302 + onRealNumberBlur(item, idx, field) {
  303 + const s = String((item && item[field]) || '')
  304 + if (s === '') { if (typeof idx === 'number') this.$set(this.items, idx, { ...item }); return }
  305 + const n = Number(s)
  306 + if (isNaN(n)) item[field] = ''
  307 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  308 + },
  309 + // 限制输入为2位小数
  310 + onTwoDecimalInput(val, item, idx, field) {
  311 + let v = String(val != null ? val : (item && item[field]) || '')
  312 + v = v.replace(/[^0-9.]/g, '')
  313 + v = v.replace(/(\..*)\./g, '$1')
  314 +
  315 + // Restrict to 2 decimal places
  316 + const decimalIndex = v.indexOf('.')
  317 + if (decimalIndex !== -1 && v.length > decimalIndex + 3) {
  318 + v = v.substring(0, decimalIndex + 3)
  319 + }
  320 +
  321 + if (v.startsWith('.')) v = '0' + v
  322 +
  323 + // If the value was modified (truncated or cleaned)
  324 + if (String(val) !== v) {
  325 + // Hack: Temporarily set the dirty value to trigger Vue update mechanism
  326 + // This ensures that when we set the clean value back, Vue detects a change
  327 + item[field] = val
  328 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  329 +
  330 + // Then revert to the clean value asynchronously
  331 + setTimeout(() => {
  332 + item[field] = v
  333 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  334 + }, 0)
  335 + } else {
  336 + item[field] = v
  337 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  338 + }
  339 + },
  340 + onTwoDecimalBlur(item, idx, field) {
  341 + let v = String((item && item[field]) || '')
  342 + const num = Number(v)
  343 + if (isNaN(num) || num < 0) {
  344 + item[field] = '0'
  345 + } else {
  346 + if (v.endsWith('.')) {
  347 + item[field] = v.slice(0, -1)
  348 + }
  349 + }
  350 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  351 + },
  352 + toggleViewCollapse() {
  353 + this.collapsedView = !this.collapsedView
  354 + },
  355 + onDeliveryChange(e, item, idx) {
  356 + const getStr = (x) => {
  357 + if (x && x.detail && x.detail.value !== undefined) return x.detail.value
  358 + if (typeof x === 'string') return x
  359 + return item && item.deliveryDate ? item.deliveryDate : ''
  360 + }
  361 + const val = getStr(e)
  362 + if (!val || !this.orderDate) return
  363 + const parse = (s) => {
  364 + const p = String(s).replace(/\//g, '-').split('-')
  365 + const y = Number(p[0])
  366 + const m = Number(p[1])
  367 + const d = Number(p[2])
  368 + return new Date(y, m - 1, d)
  369 + }
  370 + const sel = parse(val)
  371 + const ord = parse(this.orderDate)
  372 + if (!(sel > ord)) {
  373 + item.deliveryDate = ''
  374 + this.$set(this.items, idx, { ...item })
  375 + uni.showToast({ title: '发货日期必须大于订货日期', icon: 'none' })
  376 + }
  377 + },
  378 + openProductSheet(idx, mode = 'provideSamples') {
  379 + let opts = []
  380 + let title = ''
  381 + let value = ''
  382 + const item = this.items[idx]
  383 +
  384 + if (mode === 'provideSamples') {
  385 + opts = this.provideSamplesOptions
  386 + value = item.provideSamples
  387 + title = '选择是否提供样品'
  388 + } else if (mode === 'clearParameters') {
  389 + opts = this.clearParametersOptions;
  390 + value = item.clearParameters
  391 + title = '是否提供明确参数'
  392 + }
  393 + console.log('____', { ...this.sheet, visible: true, title, options: opts, idx, value, mode })
  394 + this.sheet = { ...this.sheet, visible: true, title, options: opts, idx, value, mode }
  395 + },
  396 + onProductConfirm({ value, label }) {
  397 + const idx = this.sheet.idx
  398 + const _mode = this.sheet.mode;
  399 + const it = this.items[idx]
  400 + if (!it) { this.sheet.visible = false; return }
  401 + it[_mode] = value
  402 + it[_mode + 'Name'] = label || ''
  403 + this.$set(this.items, idx, it)
  404 + this.sheet.visible = false
  405 + this.emitChange()
  406 + },
  407 + }
  408 +}
  409 +</script>
  410 +<style lang="scss" scoped>
  411 +.header {
  412 + background-color: #fff;
  413 + display: flex;
  414 + align-items: center;
  415 + padding: 24rpx 32rpx;
  416 +
  417 + &.bp {
  418 + border-bottom: 1px solid #f0f0f0;
  419 + }
  420 +}
  421 +
  422 +.dot {
  423 + width: 16rpx;
  424 + height: 16rpx;
  425 + background: #3D48A3;
  426 + border-radius: 50%;
  427 + margin-right: 12rpx;
  428 +}
  429 +
  430 +.title {
  431 + font-size: 32rpx;
  432 + color: rgba(0, 0, 0, 0.9);
  433 + font-weight: 600;
  434 +}
  435 +
  436 +.ops {
  437 + margin-left: auto;
  438 +}
  439 +
  440 +.op {
  441 + color: $theme-primary;
  442 + font-size: 28rpx;
  443 + margin-left: 8rpx;
  444 +}
  445 +
  446 +.op1 {
  447 + display: flex;
  448 + align-items: center;
  449 +}
  450 +
  451 +.opAdd {
  452 + color: rgba(0, 0, 0, 0.6);
  453 + width: 40rpx;
  454 + height: 40rpx;
  455 +}
  456 +
  457 +.opCollapse {
  458 + color: rgba(0, 0, 0, 0.6);
  459 + width: 32rpx;
  460 + height: 28rpx;
  461 + margin-right: 16rpx;
  462 +}
  463 +
  464 +::v-deep .uni-list {
  465 + background: transparent;
  466 +
  467 + .uni-list--border-top {
  468 + background-color: transparent !important;
  469 + }
  470 +
  471 + &-item {
  472 + &__extra-text {
  473 + font-size: 32rpx;
  474 + }
  475 +
  476 + &__content-title {
  477 + font-size: 32rpx;
  478 + color: rgba(0, 0, 0, 0.9);
  479 + }
  480 +
  481 + &__container {
  482 + padding: 32rpx;
  483 +
  484 + .uni-easyinput {
  485 +
  486 + .is-disabled {
  487 + background-color: transparent !important;
  488 + }
  489 +
  490 + &__placeholder-class {
  491 + font-size: 32rpx;
  492 + color: rgba(0, 0, 0, 0.4);
  493 + }
  494 +
  495 + &__content {
  496 + border: none;
  497 +
  498 + &-input {
  499 + padding-left: 0 !important;
  500 + height: 48rpx;
  501 + line-height: 48rpx;
  502 + font-size: 32rpx;
  503 + }
  504 +
  505 + .content-clear-icon {
  506 + font-size: 44rpx !important;
  507 + }
  508 + }
  509 + }
  510 +
  511 + .amount-row {
  512 + flex: 1;
  513 + display: flex;
  514 + align-items: center;
  515 +
  516 + .uni-easyinput {
  517 + flex: 1;
  518 + }
  519 +
  520 + .unit {
  521 + margin-left: 16rpx;
  522 + color: rgba(0, 0, 0, 0.9);
  523 + }
  524 + }
  525 +
  526 + .item-title,
  527 + .uni-list-item__content {
  528 + flex: none;
  529 + min-height: 48rpx;
  530 + line-height: 48rpx;
  531 + font-size: 32rpx;
  532 + position: relative;
  533 + width: 210rpx;
  534 + margin-right: 32rpx;
  535 + color: rgba(0, 0, 0, 0.9);
  536 + padding-right: 0;
  537 +
  538 +
  539 + .required {
  540 + color: red;
  541 + position: absolute;
  542 + top: 50%;
  543 + transform: translateY(-50%);
  544 + left: -16rpx;
  545 + }
  546 + }
  547 +
  548 + }
  549 +
  550 + &.select-item {
  551 + &.is-empty {
  552 + .uni-list-item__extra-text {
  553 + color: rgba(0, 0, 0, 0.4) !important;
  554 + }
  555 + }
  556 +
  557 + &.is-filled {
  558 + .uni-list-item__extra-text {
  559 + color: rgba(0, 0, 0, 0.9) !important;
  560 + }
  561 + }
  562 +
  563 + .serial-number-row {
  564 + display: flex;
  565 + align-items: center;
  566 + }
  567 +
  568 + }
  569 +
  570 + &.mgb10 {
  571 + margin-bottom: 20rpx;
  572 + }
  573 +
  574 + }
  575 +
  576 + .title-header {
  577 + background-color: #fff;
  578 + display: flex;
  579 + align-items: center;
  580 + padding: 32rpx 32rpx 22rpx;
  581 +
  582 + &_icon {
  583 + width: 32rpx;
  584 + height: 28rpx;
  585 + margin-right: 16rpx;
  586 + }
  587 +
  588 + span {
  589 + color: rgba(0, 0, 0, 0.9);
  590 + font-size: 32rpx;
  591 + line-height: 44rpx;
  592 + font-weight: 600;
  593 + }
  594 + }
  595 +}
  596 +
  597 +/* 只读 easyinput 根据内容自适应高度 */
  598 +::v-deep .uni-list-item__container {
  599 + align-items: flex-start;
  600 +}
  601 +
  602 +.block-ops {
  603 + display: flex;
  604 + padding: 20rpx 32rpx 20rpx;
  605 + justify-content: space-around;
  606 +}
  607 +
  608 +.del {
  609 + color: #D54941;
  610 + font-size: 28rpx;
  611 + display: flex;
  612 + align-items: center;
  613 +
  614 + image {
  615 + width: 40rpx;
  616 + height: 40rpx;
  617 + }
  618 +}
  619 +
  620 +.toggle {
  621 + color: $theme-primary;
  622 + font-size: 28rpx;
  623 + display: flex;
  624 + align-items: center;
  625 +
  626 + image {
  627 + width: 40rpx;
  628 + height: 40rpx;
  629 + }
  630 +}
  631 +
  632 +.section {
  633 + background: #f1f1f1;
  634 + margin-bottom: 20rpx;
  635 +
  636 + .block {
  637 + background: #ffffff;
  638 + // padding: 32rpx 0;
  639 + margin-bottom: 20rpx;
  640 +
  641 + &:last-child {
  642 + margin-bottom: 0;
  643 + }
  644 + }
  645 +
  646 + .row {
  647 + display: flex;
  648 + // margin-bottom: 24rpx;
  649 + line-height: 32rpx;
  650 + padding: 32rpx;
  651 + border-bottom: 1rpx solid #f2f2f2 !important;
  652 +
  653 +
  654 + &.noneStyle {
  655 + border-bottom: 0;
  656 + border-bottom: none;
  657 + }
  658 +
  659 + &.row-spec {
  660 + align-items: center;
  661 + }
  662 + }
  663 +
  664 + .row:last-child {
  665 + margin-bottom: 0;
  666 + }
  667 +
  668 + .label {
  669 + width: 210rpx;
  670 + margin-right: 32rpx;
  671 + color: rgba(0, 0, 0, 0.9);
  672 + font-size: 32rpx;
  673 + line-height: 48rpx;
  674 + }
  675 +
  676 + .value {
  677 + flex: 1;
  678 + color: rgba(0, 0, 0, 0.9);
  679 + font-size: 32rpx;
  680 + white-space: pre-wrap;
  681 + word-break: break-all;
  682 + line-height: 48rpx;
  683 + }
  684 +
  685 + .value-spec {
  686 + height: 48rpx;
  687 + display: flex;
  688 + align-items: center;
  689 + color: #000000;
  690 +
  691 + &_box {
  692 + position: relative;
  693 + width: 60rpx;
  694 + height: 48rpx;
  695 +
  696 + &_1 {
  697 + font-size: 16rpx;
  698 + position: absolute;
  699 + top: -10rpx;
  700 + left: 0;
  701 + }
  702 +
  703 + &_2 {
  704 + font-size: 16rpx;
  705 + position: absolute;
  706 + bottom: -10rpx;
  707 + left: 0;
  708 + }
  709 + }
  710 +
  711 + &_val {
  712 + font-size: 28rpx;
  713 +
  714 + &.p12 {
  715 + padding-right: 12rpx;
  716 + }
  717 + }
  718 + }
  719 +
  720 + .view-total {
  721 + padding-top: 20rpx;
  722 +
  723 + .head {
  724 + font-size: 32rpx;
  725 + font-weight: 600;
  726 + line-height: 50rpx;
  727 + color: rgba(0, 0, 0, 0.9);
  728 + padding-bottom: 16rpx;
  729 + margin-bottom: 24rpx;
  730 + border-bottom: 1px dashed #E7E7E7;
  731 + }
  732 +
  733 + .row {
  734 + display: flex;
  735 + margin-bottom: 24rpx;
  736 + line-height: 32rpx;
  737 +
  738 + .label {
  739 + width: 180rpx;
  740 + margin-right: 14rpx;
  741 + color: rgba(0, 0, 0, 0.6);
  742 + font-size: 28rpx;
  743 + }
  744 +
  745 + .value {
  746 + flex: 1;
  747 + color: rgba(0, 0, 0, 0.9);
  748 + font-size: 28rpx;
  749 + white-space: pre-wrap;
  750 + word-break: break-all;
  751 + }
  752 + }
  753 + }
  754 +}
  755 +
  756 +
  757 +.view-list {
  758 + padding: 26rpx 32rpx;
  759 + background: #ffffff;
  760 +
  761 + .card {
  762 + background: #f3f3f3;
  763 + border-radius: 16rpx;
  764 + padding: 32rpx 44rpx;
  765 + margin-bottom: 20rpx;
  766 +
  767 + &:last-child {
  768 + margin-bottom: 0;
  769 + }
  770 + }
  771 +
  772 + .row {
  773 + display: flex;
  774 + margin-bottom: 24rpx;
  775 + line-height: 32rpx;
  776 +
  777 + &.row-spec {
  778 + height: 60rpx;
  779 + align-items: center;
  780 + }
  781 + }
  782 +
  783 + .row:last-child {
  784 + margin-bottom: 0;
  785 + }
  786 +
  787 + .label {
  788 + width: 200rpx;
  789 + margin-right: 14rpx;
  790 + color: rgba(0, 0, 0, 0.6);
  791 + font-size: 28rpx;
  792 + }
  793 +
  794 + .value {
  795 + flex: 1;
  796 + color: rgba(0, 0, 0, 0.9);
  797 + font-size: 28rpx;
  798 + white-space: pre-wrap;
  799 + word-break: break-all;
  800 + }
  801 +
  802 + .value-spec {
  803 + height: 60rpx;
  804 + display: flex;
  805 + align-items: center;
  806 + color: #000000;
  807 +
  808 + &_box {
  809 + position: relative;
  810 + width: 60rpx;
  811 + height: 60rpx;
  812 +
  813 + &_1 {
  814 + font-size: 16rpx;
  815 + position: absolute;
  816 + top: 0;
  817 + left: 0;
  818 + }
  819 +
  820 + &_2 {
  821 + font-size: 16rpx;
  822 + position: absolute;
  823 + bottom: 0;
  824 + left: 0;
  825 + }
  826 + }
  827 +
  828 + &_val {
  829 + font-size: 28rpx;
  830 +
  831 + &.p12 {
  832 + padding-right: 12rpx;
  833 + }
  834 + }
  835 + }
  836 +
  837 + .view-total {
  838 + padding-top: 20rpx;
  839 +
  840 + .head {
  841 + font-size: 32rpx;
  842 + font-weight: 600;
  843 + line-height: 50rpx;
  844 + color: rgba(0, 0, 0, 0.9);
  845 + padding-bottom: 16rpx;
  846 + margin-bottom: 24rpx;
  847 + border-bottom: 1px dashed #E7E7E7;
  848 + }
  849 +
  850 + .row {
  851 + display: flex;
  852 + margin-bottom: 24rpx;
  853 + line-height: 32rpx;
  854 +
  855 + .label {
  856 + width: 180rpx;
  857 + margin-right: 14rpx;
  858 + color: rgba(0, 0, 0, 0.6);
  859 + font-size: 28rpx;
  860 + }
  861 +
  862 + .value {
  863 + flex: 1;
  864 + color: rgba(0, 0, 0, 0.9);
  865 + font-size: 28rpx;
  866 + white-space: pre-wrap;
  867 + word-break: break-all;
  868 + }
  869 + }
  870 + }
  871 +}
  872 +</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.orderingUnitName }}</text>
  7 + <view :class="['status', `status_${form.status}`]" />
  8 + <view class="row"><text class="label">试样种类</text><text class="value">{{ form.sampleTypeName }}</text></view>
  9 + <view class="row"><text class="label">客户类型</text><text class="value">{{ form.customerTypeName }}</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.belongingBreed }}</text></view>
  12 + <view class="row"><text class="label">原供货同行</text><text class="value">{{ form.originalSupplierPeer }}</text>
  13 + </view>
  14 + </view>
  15 +
  16 + <!-- 产品 -->
  17 + <view class="section2">
  18 + <Product mode="view" :list="form.productSampleConfirmationSlipDetailList" />
  19 + </view>
  20 +
  21 + <view class="section">
  22 + <view class="row"><text class="label">数量</text><text class="value">{{ form.totalQuantity }}</text></view>
  23 + <view class="row"><text class="label">本次试样数量是否超规定</text><text class="value">{{ form.sampleQuantityRegulation ?
  24 + '是' : '否' }}</text></view>
  25 + <view class="row"><text class="label">试样规格个数是否超规定</text><text class="value">{{
  26 + form.specificationQuantityRegulation ? '是' : '否' }}</text></view>
  27 + <view class="row"><text class="label">试样次数</text><text class="value">{{ form.sampleFrequency }}</text></view>
  28 + <view class="row"><text class="label">前期不合格描述</text><text class="value">{{ form.earlyNonconformityDescription
  29 + }}</text></view>
  30 + </view>
  31 + </view>
  32 + </scroll-view>
  33 + </view>
  34 +</template>
  35 +
  36 +<script>
  37 +import { getDetailApi } from '@/api/confirmation_form.js'
  38 +import Product from './product.vue'
  39 +
  40 +export default {
  41 + name: 'ConfirmationFormViewer',
  42 + components: { Product },
  43 + props: { id: { type: [String, Number], default: '' } },
  44 + data() {
  45 + return {
  46 + form: {},
  47 + }
  48 + },
  49 + computed: {
  50 + },
  51 + watch: {
  52 + id: {
  53 + immediate: true,
  54 + handler(val) {
  55 + const v = (val !== undefined && val !== null) ? String(val) : ''
  56 + if (v) this.loadDetail(v)
  57 + }
  58 + }
  59 + },
  60 + onLoad(query) {
  61 + },
  62 + methods: {
  63 + async loadDetail(id) {
  64 + try {
  65 + const res = await getDetailApi(id)
  66 + this.form = res.data || {}
  67 + } catch (e) {
  68 + this.form = {}
  69 + }
  70 + },
  71 + }
  72 +}
  73 +</script>
  74 +
  75 +<style lang="scss" scoped>
  76 +.page {
  77 + display: flex;
  78 + flex-direction: column;
  79 + height: 100vh;
  80 +}
  81 +
  82 +.scroll {
  83 + flex: 1;
  84 + background: #f3f3f3;
  85 +}
  86 +
  87 +.detail-page {
  88 + padding-bottom: 20rpx;
  89 +}
  90 +
  91 +.section {
  92 + padding: 32rpx;
  93 + background: #fff;
  94 + margin-bottom: 20rpx;
  95 + position: relative;
  96 +
  97 +}
  98 +
  99 +.row {
  100 + display: flex;
  101 + margin-bottom: 28rpx;
  102 +
  103 + &:last-child {
  104 + margin-bottom: 0;
  105 + }
  106 +
  107 + &.company {
  108 + font-size: 36rpx;
  109 + font-weight: 600;
  110 + color: rgba(0, 0, 0, 0.9);
  111 + padding-top: 10rpx;
  112 + margin-bottom: 32rpx;
  113 + line-height: 50rpx;
  114 + }
  115 +
  116 + .label {
  117 + max-width: 400rpx;
  118 + margin-right: 20rpx;
  119 + line-height: 32rpx;
  120 + font-size: 28rpx;
  121 + color: rgba(0, 0, 0, 0.6);
  122 + }
  123 +
  124 + .value {
  125 + flex: 1;
  126 + line-height: 32rpx;
  127 + font-size: 28rpx;
  128 + color: rgba(0, 0, 0, 0.9);
  129 + text-align: right;
  130 + word-break: break-all;
  131 + }
  132 +}
  133 +
  134 +.title-header {
  135 + background-color: #fff;
  136 + display: flex;
  137 + align-items: center;
  138 + padding: 32rpx 32rpx 22rpx;
  139 + border-bottom: 1rpx dashed #f0f0f0;
  140 +
  141 + &_icon {
  142 + width: 32rpx;
  143 + height: 28rpx;
  144 + margin-right: 16rpx;
  145 + }
  146 +
  147 + span {
  148 + color: rgba(0, 0, 0, 0.9);
  149 + font-size: 32rpx;
  150 + line-height: 44rpx;
  151 + font-weight: 600;
  152 + }
  153 +}
  154 +</style>
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 <view v-if="mode === 'add'" class="add-list"> 16 <view v-if="mode === 'add'" class="add-list">
17 <view v-for="(item, idx) in items" :key="idx" class="block"> 17 <view v-for="(item, idx) in items" :key="idx" class="block">
18 <uni-list v-show="item.collapsed"> 18 <uni-list v-show="item.collapsed">
19 - <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.productName || '请选择产品名称'" showArrow> 19 + <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx, 'product')" :rightText="item.productName || '请选择产品名称'" showArrow>
20 <template v-slot:body> 20 <template v-slot:body>
21 <view class="item-title"><text>产品名称</text></view> 21 <view class="item-title"><text>产品名称</text></view>
22 </template> 22 </template>
@@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
33 </uni-list-item> 33 </uni-list-item>
34 </uni-list> 34 </uni-list>
35 <uni-list v-show="!item.collapsed"> 35 <uni-list v-show="!item.collapsed">
36 - <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.productName || '请选择产品名称'" showArrow> 36 + <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx, 'product')" :rightText="item.productName || '请选择产品名称'" showArrow>
37 <template v-slot:body> 37 <template v-slot:body>
38 <view class="item-title"><text>产品名称</text></view> 38 <view class="item-title"><text>产品名称</text></view>
39 </template> 39 </template>
@@ -137,6 +137,12 @@ @@ -137,6 +137,12 @@
137 <uni-datetime-picker :start="minDeliveryDate" type="date" v-model="item.deliveryDate" @change="onDateChange(idx, $event)" /> 137 <uni-datetime-picker :start="minDeliveryDate" type="date" v-model="item.deliveryDate" @change="onDateChange(idx, $event)" />
138 </template> 138 </template>
139 </uni-list-item> 139 </uni-list-item>
  140 + <uni-list-item class="select-item" :class="typeof item.sampleOrder === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  141 + @click="openProductSheet(idx, 'sampleOrder')" :rightText="typeof item.sampleOrder === 'boolean' ? (item.sampleOrder ? '是' : '否') : '请选择'" showArrow>
  142 + <template v-slot:body>
  143 + <view class="item-title"><text>是否为试样订单</text></view>
  144 + </template>
  145 + </uni-list-item>
140 </uni-list> 146 </uni-list>
141 <view class="block-ops"> 147 <view class="block-ops">
142 <div class="del" @click="onRemove(idx)"> 148 <div class="del" @click="onRemove(idx)">
@@ -195,6 +201,7 @@ @@ -195,6 +201,7 @@
195 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount) 201 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount)
196 }}</text></view> 202 }}</text></view>
197 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view> 203 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view>
  204 + <view class="row"><text class="label">是否为试样订单</text><text class="value">{{ item.sampleOrder ? '是' : '否' }}</text></view>
198 </view> 205 </view>
199 </view> 206 </view>
200 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" /> 207 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" />
@@ -217,7 +224,7 @@ export default { @@ -217,7 +224,7 @@ export default {
217 return { 224 return {
218 items: [], 225 items: [],
219 collapsedView: false, 226 collapsedView: false,
220 - sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1 } 227 + sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1, mode: 'product' }
221 } 228 }
222 }, 229 },
223 computed: { 230 computed: {
@@ -251,20 +258,20 @@ export default { @@ -251,20 +258,20 @@ export default {
251 handler(v) { 258 handler(v) {
252 // const arr = Array.isArray(v) ? v : [] 259 // const arr = Array.isArray(v) ? v : []
253 // this.items = arr.map(x => ({ ...this.defaultItem(), ...x, collapsed: true })) 260 // this.items = arr.map(x => ({ ...this.defaultItem(), ...x, collapsed: true }))
254 - this.items = v.map(x => ({ ...this.defaultItem(), ...x, collapsed: true })) 261 + this.items = v.map(x => ({ ...this.defaultItem(), ...x, sampleOrder: !!x.sampleOrder, collapsed: true }))
255 console.log('v', v) 262 console.log('v', v)
256 }, 263 },
257 deep: true 264 deep: true
258 } 265 }
259 }, 266 },
260 created() { 267 created() {
261 - const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }] 268 + const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, sampleOrder: !!v.sampleOrder, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }]
262 this.items = init 269 this.items = init
263 this.recalculateAll() 270 this.recalculateAll()
264 }, 271 },
265 methods: { 272 methods: {
266 defaultItem() { 273 defaultItem() {
267 - return { productId: '', productName: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '',processingFee: undefined, status: '', quantity: '', unitPrice: '', totalAmount: 0, deliveryDate: '' } 274 + return { productId: '', productName: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', status: '', quantity: '', unitPrice: '', processingFee: undefined, totalAmount: 0, deliveryDate: '', sampleOrder: false }
268 }, 275 },
269 onNonNegativeInput(idx, field) { 276 onNonNegativeInput(idx, field) {
270 const it = this.items[idx] 277 const it = this.items[idx]
@@ -373,18 +380,38 @@ export default { @@ -373,18 +380,38 @@ export default {
373 const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/') 380 const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/')
374 return [t, w, l].filter(Boolean).join(' × ') 381 return [t, w, l].filter(Boolean).join(' × ')
375 }, 382 },
376 - openProductSheet(idx) {  
377 - const opts = this.selectOptions  
378 - const current = this.items[idx] && this.items[idx].productId  
379 - const match = opts.find(o => o.value === current)  
380 - this.sheet = { ...this.sheet, visible: true, title: '请选择产品', options: opts, idx, value: match ? match.value : '' } 383 + openProductSheet(idx, mode = 'product') {
  384 + let opts = []
  385 + let title = ''
  386 + let value = ''
  387 + const item = this.items[idx]
  388 +
  389 + if (mode === 'product') {
  390 + opts = this.selectOptions
  391 + const current = item && item.productId
  392 + const match = opts.find(o => o.value === current)
  393 + value = match ? match.value : ''
  394 + title = '请选择产品'
  395 + } else if (mode === 'sampleOrder') {
  396 + opts = [{ label: '是', value: true }, { label: '否', value: false }]
  397 + value = item.sampleOrder
  398 + title = '是否为试样订单'
  399 + }
  400 +
  401 + this.sheet = { ...this.sheet, visible: true, title, options: opts, idx, value, mode }
381 }, 402 },
382 onProductConfirm({ value, label }) { 403 onProductConfirm({ value, label }) {
383 - const idx = this.sheet.idx 404 + const { idx, mode } = this.sheet
384 const it = this.items[idx] 405 const it = this.items[idx]
385 if (!it) { this.sheet.visible = false; return } 406 if (!it) { this.sheet.visible = false; return }
386 - it.productId = value  
387 - it.productName = label || '' 407 +
  408 + if (mode === 'product') {
  409 + it.productId = value
  410 + it.productName = label || ''
  411 + } else if (mode === 'sampleOrder') {
  412 + it.sampleOrder = value
  413 + }
  414 +
388 this.$set(this.items, idx, it) 415 this.$set(this.items, idx, it)
389 this.sheet.visible = false 416 this.sheet.visible = false
390 this.emitChange() 417 this.emitChange()
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 <view v-if="mode === 'add'" class="add-list"> 16 <view v-if="mode === 'add'" class="add-list">
17 <view v-for="(item, idx) in items" :key="idx" class="block"> 17 <view v-for="(item, idx) in items" :key="idx" class="block">
18 <uni-list v-show="item.collapsed"> 18 <uni-list v-show="item.collapsed">
19 - <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.productName || '请选择产品名称'" showArrow> 19 + <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx, 'product')" :rightText="item.productName || '请选择产品名称'" showArrow>
20 <template v-slot:body> 20 <template v-slot:body>
21 <view class="item-title"><text>产品名称</text></view> 21 <view class="item-title"><text>产品名称</text></view>
22 </template> 22 </template>
@@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
33 </uni-list-item> 33 </uni-list-item>
34 </uni-list> 34 </uni-list>
35 <uni-list v-show="!item.collapsed"> 35 <uni-list v-show="!item.collapsed">
36 - <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.productName || '请选择产品名称'" showArrow> 36 + <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx, 'product')" :rightText="item.productName || '请选择产品名称'" showArrow>
37 <template v-slot:body> 37 <template v-slot:body>
38 <view class="item-title"><text>产品名称</text></view> 38 <view class="item-title"><text>产品名称</text></view>
39 </template> 39 </template>
@@ -139,6 +139,12 @@ @@ -139,6 +139,12 @@
139 <uni-datetime-picker :start="minDeliveryDate" type="date" v-model="item.deliveryDate" @change="onDateChange(idx, $event)" /> 139 <uni-datetime-picker :start="minDeliveryDate" type="date" v-model="item.deliveryDate" @change="onDateChange(idx, $event)" />
140 </template> 140 </template>
141 </uni-list-item> 141 </uni-list-item>
  142 + <uni-list-item class="select-item" :class="typeof item.sampleOrder === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  143 + @click="openProductSheet(idx, 'sampleOrder')" :rightText="typeof item.sampleOrder === 'boolean' ? (item.sampleOrder ? '是' : '否') : '请选择'" showArrow>
  144 + <template v-slot:body>
  145 + <view class="item-title"><text>是否为试样订单</text></view>
  146 + </template>
  147 + </uni-list-item>
142 </uni-list> 148 </uni-list>
143 <view class="block-ops"> 149 <view class="block-ops">
144 <div class="del" @click="onRemove(idx)"> 150 <div class="del" @click="onRemove(idx)">
@@ -197,6 +203,7 @@ @@ -197,6 +203,7 @@
197 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount) 203 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount)
198 }}</text></view> 204 }}</text></view>
199 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view> 205 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view>
  206 + <view class="row"><text class="label">是否为试样订单</text><text class="value">{{ item.sampleOrder ? '是' : '否' }}</text></view>
200 </view> 207 </view>
201 </view> 208 </view>
202 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" /> 209 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" />
@@ -219,7 +226,7 @@ export default { @@ -219,7 +226,7 @@ export default {
219 return { 226 return {
220 items: [], 227 items: [],
221 collapsedView: false, 228 collapsedView: false,
222 - sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1 } 229 + sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1, mode: 'product' }
223 } 230 }
224 }, 231 },
225 watch: { 232 watch: {
@@ -231,14 +238,14 @@ export default { @@ -231,14 +238,14 @@ export default {
231 handler(v) { 238 handler(v) {
232 // const arr = Array.isArray(v) ? v : [] 239 // const arr = Array.isArray(v) ? v : []
233 // this.items = arr.map(x => ({ ...this.defaultItem(), ...x, collapsed: true })) 240 // this.items = arr.map(x => ({ ...this.defaultItem(), ...x, collapsed: true }))
234 - this.items = v.map(x => ({ ...this.defaultItem(), ...x, collapsed: true })) 241 + this.items = v.map(x => ({ ...this.defaultItem(), ...x, sampleOrder: !!x.sampleOrder, collapsed: true }))
235 console.log('v', v) 242 console.log('v', v)
236 }, 243 },
237 deep: true 244 deep: true
238 } 245 }
239 }, 246 },
240 created() { 247 created() {
241 - const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }] 248 + const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, sampleOrder: !!v.sampleOrder, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }]
242 this.items = init 249 this.items = init
243 this.recalculateAll() 250 this.recalculateAll()
244 }, 251 },
@@ -266,7 +273,7 @@ export default { @@ -266,7 +273,7 @@ export default {
266 }, 273 },
267 methods: { 274 methods: {
268 defaultItem() { 275 defaultItem() {
269 - return { productId: '', productName: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', status: '', quantity: '', unitPrice: '', processingFee: undefined, totalAmount: 0, deliveryDate: '' } 276 + return { productId: '', productName: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', status: '', quantity: '', unitPrice: '', processingFee: undefined, totalAmount: 0, deliveryDate: '', sampleOrder: false }
270 }, 277 },
271 onNonNegativeInput(idx, field) { 278 onNonNegativeInput(idx, field) {
272 const it = this.items[idx] 279 const it = this.items[idx]
@@ -343,18 +350,38 @@ export default { @@ -343,18 +350,38 @@ export default {
343 const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/') 350 const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/')
344 return [t, w, l].filter(Boolean).join(' × ') 351 return [t, w, l].filter(Boolean).join(' × ')
345 }, 352 },
346 - openProductSheet(idx) {  
347 - const opts = Array.isArray(this.selectOptions) ? this.selectOptions : []  
348 - const current = this.items[idx] && this.items[idx].productId  
349 - const match = (opts || []).find(o => String(o.value) === String(current))  
350 - this.sheet = { ...this.sheet, visible: true, title: '请选择产品', options: opts, idx, value: match ? match.value : '' } 353 + openProductSheet(idx, mode = 'product') {
  354 + let opts = []
  355 + let title = ''
  356 + let value = ''
  357 + const item = this.items[idx]
  358 +
  359 + if (mode === 'product') {
  360 + opts = Array.isArray(this.selectOptions) ? this.selectOptions : []
  361 + const current = item && item.productId
  362 + const match = (opts || []).find(o => String(o.value) === String(current))
  363 + value = match ? match.value : ''
  364 + title = '请选择产品'
  365 + } else if (mode === 'sampleOrder') {
  366 + opts = [{ label: '是', value: true }, { label: '否', value: false }]
  367 + value = item.sampleOrder
  368 + title = '是否为试样订单'
  369 + }
  370 +
  371 + this.sheet = { ...this.sheet, visible: true, title, options: opts, idx, value, mode }
351 }, 372 },
352 onProductConfirm({ value, label }) { 373 onProductConfirm({ value, label }) {
353 - const idx = this.sheet.idx 374 + const { idx, mode } = this.sheet
354 const it = this.items[idx] 375 const it = this.items[idx]
355 if (!it) { this.sheet.visible = false; return } 376 if (!it) { this.sheet.visible = false; return }
356 - it.productId = value  
357 - it.productName = label || '' 377 +
  378 + if (mode === 'product') {
  379 + it.productId = value
  380 + it.productName = label || ''
  381 + } else if (mode === 'sampleOrder') {
  382 + it.sampleOrder = value
  383 + }
  384 +
358 this.$set(this.items, idx, it) 385 this.$set(this.items, idx, it)
359 this.sheet.visible = false 386 this.sheet.visible = false
360 this.emitChange() 387 this.emitChange()
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 <view v-if="mode === 'add'" class="add-list"> 16 <view v-if="mode === 'add'" class="add-list">
17 <view v-for="(item, idx) in items" :key="idx" class="block"> 17 <view v-for="(item, idx) in items" :key="idx" class="block">
18 <uni-list v-show="item.collapsed"> 18 <uni-list v-show="item.collapsed">
19 - <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.productName || '请选择产品名称'" showArrow> 19 + <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx, 'product')" :rightText="item.productName || '请选择产品名称'" showArrow>
20 <template v-slot:body> 20 <template v-slot:body>
21 <view class="item-title"><text>产品名称</text></view> 21 <view class="item-title"><text>产品名称</text></view>
22 </template> 22 </template>
@@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
33 </uni-list-item> 33 </uni-list-item>
34 </uni-list> 34 </uni-list>
35 <uni-list v-show="!item.collapsed"> 35 <uni-list v-show="!item.collapsed">
36 - <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.productName || '请选择产品名称'" showArrow> 36 + <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx, 'product')" :rightText="item.productName || '请选择产品名称'" showArrow>
37 <template v-slot:body> 37 <template v-slot:body>
38 <view class="item-title"><text>产品名称</text></view> 38 <view class="item-title"><text>产品名称</text></view>
39 </template> 39 </template>
@@ -137,6 +137,12 @@ @@ -137,6 +137,12 @@
137 <uni-datetime-picker :start="minDeliveryDate" type="date" v-model="item.deliveryDate" @change="onDateChange(idx, $event)" /> 137 <uni-datetime-picker :start="minDeliveryDate" type="date" v-model="item.deliveryDate" @change="onDateChange(idx, $event)" />
138 </template> 138 </template>
139 </uni-list-item> 139 </uni-list-item>
  140 + <uni-list-item class="select-item" :class="typeof item.sampleOrder === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  141 + @click="openProductSheet(idx, 'sampleOrder')" :rightText="typeof item.sampleOrder === 'boolean' ? (item.sampleOrder ? '是' : '否') : '请选择'" showArrow>
  142 + <template v-slot:body>
  143 + <view class="item-title"><text>是否为试样订单</text></view>
  144 + </template>
  145 + </uni-list-item>
140 </uni-list> 146 </uni-list>
141 <view class="block-ops"> 147 <view class="block-ops">
142 <div class="del" @click="onRemove(idx)"> 148 <div class="del" @click="onRemove(idx)">
@@ -191,6 +197,7 @@ @@ -191,6 +197,7 @@
191 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount) 197 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount)
192 }}</text></view> 198 }}</text></view>
193 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view> 199 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view>
  200 + <view class="row"><text class="label">是否为试样订单</text><text class="value">{{ item.sampleOrder ? '是' : '否' }}</text></view>
194 </view> 201 </view>
195 </view> 202 </view>
196 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" /> 203 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" />
@@ -213,7 +220,7 @@ export default { @@ -213,7 +220,7 @@ export default {
213 return { 220 return {
214 items: [], 221 items: [],
215 collapsedView: false, 222 collapsedView: false,
216 - sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1 } 223 + sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1, mode: 'product' }
217 } 224 }
218 }, 225 },
219 computed: { 226 computed: {
@@ -247,20 +254,20 @@ export default { @@ -247,20 +254,20 @@ export default {
247 handler(v) { 254 handler(v) {
248 // const arr = Array.isArray(v) ? v : [] 255 // const arr = Array.isArray(v) ? v : []
249 // this.items = arr.map(x => ({ ...this.defaultItem(), ...x, collapsed: true })) 256 // this.items = arr.map(x => ({ ...this.defaultItem(), ...x, collapsed: true }))
250 - this.items = v.map(x => ({ ...this.defaultItem(), ...x, collapsed: true })) 257 + this.items = v.map(x => ({ ...this.defaultItem(), ...x, sampleOrder: !!x.sampleOrder, collapsed: true }))
251 console.log('v', v) 258 console.log('v', v)
252 }, 259 },
253 deep: true 260 deep: true
254 } 261 }
255 }, 262 },
256 created() { 263 created() {
257 - const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }] 264 + const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, sampleOrder: !!v.sampleOrder, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }]
258 this.items = init 265 this.items = init
259 this.recalculateAll() 266 this.recalculateAll()
260 }, 267 },
261 methods: { 268 methods: {
262 defaultItem() { 269 defaultItem() {
263 - return { productId: '', productName: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', status: '', quantity: '', unitPrice: '', totalAmount: 0, deliveryDate: '' } 270 + return { productId: '', productName: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', status: '', quantity: '', unitPrice: '', totalAmount: 0, deliveryDate: '', sampleOrder: false }
264 }, 271 },
265 onNonNegativeInput(idx, field) { 272 onNonNegativeInput(idx, field) {
266 const it = this.items[idx] 273 const it = this.items[idx]
@@ -380,18 +387,38 @@ export default { @@ -380,18 +387,38 @@ export default {
380 const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/') 387 const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/')
381 return [t, w, l].filter(Boolean).join(' × ') 388 return [t, w, l].filter(Boolean).join(' × ')
382 }, 389 },
383 - openProductSheet(idx) {  
384 - const opts = this.selectOptions  
385 - const current = this.items[idx] && this.items[idx].productId  
386 - const match = opts.find(o => o.value === current)  
387 - this.sheet = { ...this.sheet, visible: true, title: '请选择产品', options: opts, idx, value: match ? match.value : '' } 390 + openProductSheet(idx, mode = 'product') {
  391 + let opts = []
  392 + let title = ''
  393 + let value = ''
  394 + const item = this.items[idx]
  395 +
  396 + if (mode === 'product') {
  397 + opts = this.selectOptions
  398 + const current = item && item.productId
  399 + const match = opts.find(o => o.value === current)
  400 + value = match ? match.value : ''
  401 + title = '请选择产品'
  402 + } else if (mode === 'sampleOrder') {
  403 + opts = [{ label: '是', value: true }, { label: '否', value: false }]
  404 + value = item.sampleOrder
  405 + title = '是否为试样订单'
  406 + }
  407 +
  408 + this.sheet = { ...this.sheet, visible: true, title, options: opts, idx, value, mode }
388 }, 409 },
389 onProductConfirm({ value, label }) { 410 onProductConfirm({ value, label }) {
390 - const idx = this.sheet.idx 411 + const { idx, mode } = this.sheet
391 const it = this.items[idx] 412 const it = this.items[idx]
392 if (!it) { this.sheet.visible = false; return } 413 if (!it) { this.sheet.visible = false; return }
393 - it.productId = value  
394 - it.productName = label || '' 414 +
  415 + if (mode === 'product') {
  416 + it.productId = value
  417 + it.productName = label || ''
  418 + } else if (mode === 'sampleOrder') {
  419 + it.sampleOrder = value
  420 + }
  421 +
395 this.$set(this.items, idx, it) 422 this.$set(this.items, idx, it)
396 this.sheet.visible = false 423 this.sheet.visible = false
397 this.emitChange() 424 this.emitChange()
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 <view v-if="mode === 'add'" class="add-list"> 16 <view v-if="mode === 'add'" class="add-list">
17 <view v-for="(item, idx) in items" :key="idx" class="block"> 17 <view v-for="(item, idx) in items" :key="idx" class="block">
18 <uni-list v-show="item.collapsed"> 18 <uni-list v-show="item.collapsed">
19 - <uni-list-item class="select-item" :class="item.rawProductName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.rawProductName || '请选择原材料名称'" showArrow> 19 + <uni-list-item class="select-item" :class="item.rawProductName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx, 'product')" :rightText="item.rawProductName || '请选择原材料名称'" showArrow>
20 <template v-slot:body> 20 <template v-slot:body>
21 <view class="item-title"><text>原材料名称</text></view> 21 <view class="item-title"><text>原材料名称</text></view>
22 </template> 22 </template>
@@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
33 </uni-list-item> 33 </uni-list-item>
34 </uni-list> 34 </uni-list>
35 <uni-list v-show="!item.collapsed"> 35 <uni-list v-show="!item.collapsed">
36 - <uni-list-item class="select-item" :class="item.rawProductName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.rawProductName || '请选择原材料名称'" showArrow> 36 + <uni-list-item class="select-item" :class="item.rawProductName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx, 'product')" :rightText="item.rawProductName || '请选择原材料名称'" showArrow>
37 <template v-slot:body> 37 <template v-slot:body>
38 <view class="item-title"><text>原材料名称</text></view> 38 <view class="item-title"><text>原材料名称</text></view>
39 </template> 39 </template>
@@ -159,6 +159,12 @@ @@ -159,6 +159,12 @@
159 <uni-datetime-picker :start="minDeliveryDate" type="date" v-model="item.deliveryDate" @change="onDateChange(idx, $event)" /> 159 <uni-datetime-picker :start="minDeliveryDate" type="date" v-model="item.deliveryDate" @change="onDateChange(idx, $event)" />
160 </template> 160 </template>
161 </uni-list-item> 161 </uni-list-item>
  162 + <uni-list-item class="select-item" :class="typeof item.sampleOrder === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  163 + @click="openProductSheet(idx, 'sampleOrder')" :rightText="typeof item.sampleOrder === 'boolean' ? (item.sampleOrder ? '是' : '否') : '请选择'" showArrow>
  164 + <template v-slot:body>
  165 + <view class="item-title"><text>是否为试样订单</text></view>
  166 + </template>
  167 + </uni-list-item>
162 </uni-list> 168 </uni-list>
163 <view class="block-ops"> 169 <view class="block-ops">
164 <div class="del" @click="onRemove(idx)"> 170 <div class="del" @click="onRemove(idx)">
@@ -218,6 +224,7 @@ @@ -218,6 +224,7 @@
218 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount) 224 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount)
219 }}</text></view> 225 }}</text></view>
220 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view> 226 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view>
  227 + <view class="row"><text class="label">是否为试样订单</text><text class="value">{{ item.sampleOrder ? '是' : '否' }}</text></view>
221 </view> 228 </view>
222 </view> 229 </view>
223 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" /> 230 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" />
@@ -289,22 +296,22 @@ export default { @@ -289,22 +296,22 @@ export default {
289 }, 296 },
290 list: { 297 list: {
291 handler(v) { 298 handler(v) {
292 - this.items = v.map(x => ({ ...this.defaultItem(), ...x, collapsed: true })) 299 + this.items = v.map(x => ({ ...this.defaultItem(), ...x, sampleOrder: !!x.sampleOrder, collapsed: true }))
293 console.log('v', v) 300 console.log('v', v)
294 }, 301 },
295 deep: true 302 deep: true
296 } 303 }
297 }, 304 },
298 created() { 305 created() {
299 - const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }] 306 + const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, sampleOrder: !!v.sampleOrder, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }]
300 this.items = init 307 this.items = init
301 console.log('init', init) 308 console.log('init', init)
302 this.recalculateAll() 309 this.recalculateAll()
303 }, 310 },
304 methods: { 311 methods: {
305 - defaultItem() {  
306 - return { productId:'', productName:'', productGrade:'', productStatus:'', rawProductId: '', rawProductName: '', rawProductGrade: '', industry: '',materialProductRatioRemarks:'', supplyTime: '存料加工', materialProductRatio: '', materialProductRatioName: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', productQuantity: '', unitPrice: '', amountExcludingTax: 0, totalAmount: 0, deliveryDate: '' }  
307 - }, 312 + defaultItem() {
  313 + return { rawProductId: '', rawProductName: '', rawProductGradeId: '', rawProductGradeName: '', industry: '', quality: '', supplyTime: '', materialProductRatio: '', materialProductRatioName: '', materialProductRatioRemarks: '', productName: '', productId: '', productGrade: '', productStatus: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', productQuantity: '', unitPrice: '', amountExcludingTax: 0, totalAmount: 0, deliveryDate: '', sampleOrder: false }
  314 + },
308 onNumberInput(idx, field) { 315 onNumberInput(idx, field) {
309 const it = this.items[idx] 316 const it = this.items[idx]
310 if (!it) return 317 if (!it) return
@@ -414,11 +421,25 @@ export default { @@ -414,11 +421,25 @@ export default {
414 const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/') 421 const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/')
415 return [t, w, l].filter(Boolean).join(' × ') 422 return [t, w, l].filter(Boolean).join(' × ')
416 }, 423 },
417 - openProductSheet(idx) {  
418 - const opts = this.rawProductOptions  
419 - const current = this.items[idx] && this.items[idx].rawProductId  
420 - const match = opts.find(o => String(o.value) === String(current))  
421 - this.sheet = { ...this.sheet, visible: true, title: '请选择原材料名称', options: opts, idx, value: match ? match.value : '', mode: 'product' } 424 + openProductSheet(idx, mode = 'product') {
  425 + let opts = []
  426 + let title = ''
  427 + let value = ''
  428 + const item = this.items[idx]
  429 +
  430 + if (mode === 'product') {
  431 + opts = this.rawProductOptions
  432 + const current = item && item.rawProductId
  433 + const match = opts.find(o => String(o.value) === String(current))
  434 + value = match ? match.value : ''
  435 + title = '请选择原材料名称'
  436 + } else if (mode === 'sampleOrder') {
  437 + opts = [{ label: '是', value: true }, { label: '否', value: false }]
  438 + value = item.sampleOrder
  439 + title = '是否为试样订单'
  440 + }
  441 +
  442 + this.sheet = { ...this.sheet, visible: true, title, options: opts, idx, value, mode }
422 }, 443 },
423 openProductGradeSheet(idx) { 444 openProductGradeSheet(idx) {
424 const it = this.items[idx] 445 const it = this.items[idx]
@@ -466,6 +487,8 @@ export default { @@ -466,6 +487,8 @@ export default {
466 } else if (this.sheet.mode === 'target') { 487 } else if (this.sheet.mode === 'target') {
467 it.productId = value 488 it.productId = value
468 it.productName = label || '' 489 it.productName = label || ''
  490 + } else if (this.sheet.mode === 'sampleOrder') {
  491 + it.sampleOrder = value
469 } 492 }
470 this.$set(this.items, idx, it) 493 this.$set(this.items, idx, it)
471 this.sheet.visible = false 494 this.sheet.visible = false
@@ -478,7 +478,8 @@ export default { @@ -478,7 +478,8 @@ export default {
478 } 478 }
479 479
480 .label { 480 .label {
481 - width: 310rpx; 481 + max-width: 400rpx;
  482 + margin-right: 20rpx;
482 color: rgba(0, 0, 0, 0.6); 483 color: rgba(0, 0, 0, 0.6);
483 font-size: 28rpx; 484 font-size: 28rpx;
484 } 485 }
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 <view v-if="mode === 'add'" class="add-list"> 16 <view v-if="mode === 'add'" class="add-list">
17 <view v-for="(item, idx) in items" :key="idx" class="block"> 17 <view v-for="(item, idx) in items" :key="idx" class="block">
18 <uni-list v-show="item.collapsed"> 18 <uni-list v-show="item.collapsed">
19 - <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.productName || '请选择产品名称'" showArrow> 19 + <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx, 'product')" :rightText="item.productName || '请选择产品名称'" showArrow>
20 <template v-slot:body> 20 <template v-slot:body>
21 <view class="item-title"><text>产品名称</text></view> 21 <view class="item-title"><text>产品名称</text></view>
22 </template> 22 </template>
@@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
33 </uni-list-item> 33 </uni-list-item>
34 </uni-list> 34 </uni-list>
35 <uni-list v-show="!item.collapsed"> 35 <uni-list v-show="!item.collapsed">
36 - <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.productName || '请选择产品名称'" showArrow> 36 + <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx, 'product')" :rightText="item.productName || '请选择产品名称'" showArrow>
37 <template v-slot:body> 37 <template v-slot:body>
38 <view class="item-title"><text>产品名称</text></view> 38 <view class="item-title"><text>产品名称</text></view>
39 </template> 39 </template>
@@ -132,6 +132,12 @@ @@ -132,6 +132,12 @@
132 <uni-datetime-picker :start="minDeliveryDate" type="date" v-model="item.deliveryDate" @change="onDateChange(idx, $event)" /> 132 <uni-datetime-picker :start="minDeliveryDate" type="date" v-model="item.deliveryDate" @change="onDateChange(idx, $event)" />
133 </template> 133 </template>
134 </uni-list-item> 134 </uni-list-item>
  135 + <uni-list-item class="select-item" :class="typeof item.sampleOrder === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  136 + @click="openProductSheet(idx, 'sampleOrder')" :rightText="typeof item.sampleOrder === 'boolean' ? (item.sampleOrder ? '是' : '否') : '请选择'" showArrow>
  137 + <template v-slot:body>
  138 + <view class="item-title"><text>是否为试样订单</text></view>
  139 + </template>
  140 + </uni-list-item>
135 </uni-list> 141 </uni-list>
136 <view class="block-ops"> 142 <view class="block-ops">
137 <div class="del" @click="onRemove(idx)"> 143 <div class="del" @click="onRemove(idx)">
@@ -190,6 +196,7 @@ @@ -190,6 +196,7 @@
190 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount) 196 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount)
191 }}</text></view> 197 }}</text></view>
192 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view> 198 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view>
  199 + <view class="row"><text class="label">是否为试样订单</text><text class="value">{{ item.sampleOrder ? '是' : '否' }}</text></view>
193 </view> 200 </view>
194 </view> 201 </view>
195 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" /> 202 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" />
@@ -212,7 +219,7 @@ export default { @@ -212,7 +219,7 @@ export default {
212 return { 219 return {
213 items: [], 220 items: [],
214 collapsedView: false, 221 collapsedView: false,
215 - sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1 } 222 + sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1, mode: 'product' }
216 } 223 }
217 }, 224 },
218 computed: { 225 computed: {
@@ -247,19 +254,19 @@ export default { @@ -247,19 +254,19 @@ export default {
247 if (!v || !v.length) return 254 if (!v || !v.length) return
248 // Only update if significantly different to avoid loop/reset 255 // Only update if significantly different to avoid loop/reset
249 // For now, assuming external update wants to reset 256 // For now, assuming external update wants to reset
250 - this.items = v.map(x => ({ ...this.defaultItem(), ...x, collapsed: true })) 257 + this.items = v.map(x => ({ ...this.defaultItem(), ...x, sampleOrder: !!x.sampleOrder, collapsed: true }))
251 }, 258 },
252 deep: true 259 deep: true
253 } 260 }
254 }, 261 },
255 created() { 262 created() {
256 - const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }] 263 + const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, sampleOrder: !!v.sampleOrder, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }]
257 this.items = init 264 this.items = init
258 this.recalculateAll() 265 this.recalculateAll()
259 }, 266 },
260 methods: { 267 methods: {
261 defaultItem() { 268 defaultItem() {
262 - return { productId: '', productName: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', status: '', quantity: '', unitPrice: '', amountExcludingTax: 0, totalAmount: 0, deliveryDate: '' } 269 + return { productId: '', productName: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', status: '', quantity: '', unitPrice: '', amountExcludingTax: 0, totalAmount: 0, deliveryDate: '', sampleOrder: false }
263 }, 270 },
264 onNumberInput(idx, field) { 271 onNumberInput(idx, field) {
265 const it = this.items[idx] 272 const it = this.items[idx]
@@ -367,18 +374,38 @@ export default { @@ -367,18 +374,38 @@ export default {
367 const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/') 374 const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/')
368 return [t, w, l].filter(Boolean).join(' × ') 375 return [t, w, l].filter(Boolean).join(' × ')
369 }, 376 },
370 - openProductSheet(idx) {  
371 - const opts = this.selectOptions  
372 - const current = this.items[idx] && this.items[idx].productId  
373 - const match = opts.find(o => o.value === current)  
374 - this.sheet = { ...this.sheet, visible: true, title: '请选择产品', options: opts, idx, value: match ? match.value : '' } 377 + openProductSheet(idx, mode = 'product') {
  378 + let opts = []
  379 + let title = ''
  380 + let value = ''
  381 + const item = this.items[idx]
  382 +
  383 + if (mode === 'product') {
  384 + opts = this.selectOptions
  385 + const current = item && item.productId
  386 + const match = opts.find(o => o.value === current)
  387 + value = match ? match.value : ''
  388 + title = '请选择产品'
  389 + } else if (mode === 'sampleOrder') {
  390 + opts = [{ label: '是', value: true }, { label: '否', value: false }]
  391 + value = item.sampleOrder
  392 + title = '是否为试样订单'
  393 + }
  394 +
  395 + this.sheet = { ...this.sheet, visible: true, title, options: opts, idx, value, mode }
375 }, 396 },
376 onProductConfirm({ value, label }) { 397 onProductConfirm({ value, label }) {
377 - const idx = this.sheet.idx 398 + const { idx, mode } = this.sheet
378 const it = this.items[idx] 399 const it = this.items[idx]
379 if (!it) { this.sheet.visible = false; return } 400 if (!it) { this.sheet.visible = false; return }
380 - it.productId = value  
381 - it.productName = label || '' 401 +
  402 + if (mode === 'product') {
  403 + it.productId = value
  404 + it.productName = label || ''
  405 + } else if (mode === 'sampleOrder') {
  406 + it.sampleOrder = value
  407 + }
  408 +
382 this.$set(this.items, idx, it) 409 this.$set(this.items, idx, it)
383 this.sheet.visible = false 410 this.sheet.visible = false
384 this.emitChange() 411 this.emitChange()
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 <view v-if="mode === 'add'" class="add-list"> 16 <view v-if="mode === 'add'" class="add-list">
17 <view v-for="(item, idx) in items" :key="idx" class="block"> 17 <view v-for="(item, idx) in items" :key="idx" class="block">
18 <uni-list v-show="item.collapsed"> 18 <uni-list v-show="item.collapsed">
19 - <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.productName || '请选择产品名称'" showArrow> 19 + <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx, 'product')" :rightText="item.productName || '请选择产品名称'" showArrow>
20 <template v-slot:body> 20 <template v-slot:body>
21 <view class="item-title"><text>产品名称</text></view> 21 <view class="item-title"><text>产品名称</text></view>
22 </template> 22 </template>
@@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
33 </uni-list-item> 33 </uni-list-item>
34 </uni-list> 34 </uni-list>
35 <uni-list v-show="!item.collapsed"> 35 <uni-list v-show="!item.collapsed">
36 - <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.productName || '请选择产品名称'" showArrow> 36 + <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx, 'product')" :rightText="item.productName || '请选择产品名称'" showArrow>
37 <template v-slot:body> 37 <template v-slot:body>
38 <view class="item-title"><text>产品名称</text></view> 38 <view class="item-title"><text>产品名称</text></view>
39 </template> 39 </template>
@@ -132,6 +132,12 @@ @@ -132,6 +132,12 @@
132 <uni-datetime-picker :start="minDeliveryDate" type="date" v-model="item.deliveryDate" @change="onDateChange(idx, $event)" /> 132 <uni-datetime-picker :start="minDeliveryDate" type="date" v-model="item.deliveryDate" @change="onDateChange(idx, $event)" />
133 </template> 133 </template>
134 </uni-list-item> 134 </uni-list-item>
  135 + <uni-list-item class="select-item" :class="typeof item.sampleOrder === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  136 + @click="openProductSheet(idx, 'sampleOrder')" :rightText="typeof item.sampleOrder === 'boolean' ? (item.sampleOrder ? '是' : '否') : '请选择'" showArrow>
  137 + <template v-slot:body>
  138 + <view class="item-title"><text>是否为试样订单</text></view>
  139 + </template>
  140 + </uni-list-item>
135 </uni-list> 141 </uni-list>
136 <view class="block-ops"> 142 <view class="block-ops">
137 <div class="del" @click="onRemove(idx)"> 143 <div class="del" @click="onRemove(idx)">
@@ -190,6 +196,7 @@ @@ -190,6 +196,7 @@
190 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount) 196 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount)
191 }}</text></view> 197 }}</text></view>
192 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view> 198 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view>
  199 + <view class="row"><text class="label">是否为试样订单</text><text class="value">{{ item.sampleOrder ? '是' : '否' }}</text></view>
193 </view> 200 </view>
194 </view> 201 </view>
195 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" /> 202 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" />
@@ -212,7 +219,7 @@ export default { @@ -212,7 +219,7 @@ export default {
212 return { 219 return {
213 items: [], 220 items: [],
214 collapsedView: false, 221 collapsedView: false,
215 - sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1 } 222 + sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1, mode: 'product' }
216 } 223 }
217 }, 224 },
218 computed: { 225 computed: {
@@ -247,14 +254,14 @@ export default { @@ -247,14 +254,14 @@ export default {
247 handler(v) { 254 handler(v) {
248 // const arr = Array.isArray(v) ? v : [] 255 // const arr = Array.isArray(v) ? v : []
249 // this.items = arr.map(x => ({ ...this.defaultItem(), ...x, collapsed: true })) 256 // this.items = arr.map(x => ({ ...this.defaultItem(), ...x, collapsed: true }))
250 - this.items = v.map(x => ({ ...this.defaultItem(), ...x, collapsed: true })) 257 + this.items = v.map(x => ({ ...this.defaultItem(), ...x, sampleOrder: !!x.sampleOrder, collapsed: true }))
251 console.log('v', v) 258 console.log('v', v)
252 }, 259 },
253 deep: true 260 deep: true
254 } 261 }
255 }, 262 },
256 created() { 263 created() {
257 - const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }] 264 + const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, sampleOrder: !!v.sampleOrder, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }]
258 this.items = init 265 this.items = init
259 this.recalculateAll() 266 this.recalculateAll()
260 }, 267 },
@@ -364,7 +371,7 @@ export default { @@ -364,7 +371,7 @@ export default {
364 return true 371 return true
365 }, 372 },
366 defaultItem() { 373 defaultItem() {
367 - return { productId: '', productName: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', status: '', quantity: '', unitPrice: '', amountExcludingTax: 0, totalAmount: 0, deliveryDate: '' } 374 + return { productId: '', productName: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', status: '', quantity: '', unitPrice: '', amountExcludingTax: 0, totalAmount: 0, deliveryDate: '', sampleOrder: false }
368 }, 375 },
369 onNonNegativeInput(idx, field) { 376 onNonNegativeInput(idx, field) {
370 const it = this.items[idx] 377 const it = this.items[idx]
@@ -417,18 +424,38 @@ export default { @@ -417,18 +424,38 @@ export default {
417 const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/') 424 const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/')
418 return [t, w, l].filter(Boolean).join(' × ') 425 return [t, w, l].filter(Boolean).join(' × ')
419 }, 426 },
420 - openProductSheet(idx) {  
421 - const opts = this.selectOptions  
422 - const current = this.items[idx] && this.items[idx].productId  
423 - const match = opts.find(o => o.value === current)  
424 - this.sheet = { ...this.sheet, visible: true, title: '请选择产品', options: opts, idx, value: match ? match.value : '' } 427 + openProductSheet(idx, mode = 'product') {
  428 + let opts = []
  429 + let title = ''
  430 + let value = ''
  431 + const item = this.items[idx]
  432 +
  433 + if (mode === 'product') {
  434 + opts = this.selectOptions
  435 + const current = item && item.productId
  436 + const match = opts.find(o => o.value === current)
  437 + value = match ? match.value : ''
  438 + title = '请选择产品'
  439 + } else if (mode === 'sampleOrder') {
  440 + opts = [{ label: '是', value: true }, { label: '否', value: false }]
  441 + value = item.sampleOrder
  442 + title = '是否为试样订单'
  443 + }
  444 +
  445 + this.sheet = { ...this.sheet, visible: true, title, options: opts, idx, value, mode }
425 }, 446 },
426 onProductConfirm({ value, label }) { 447 onProductConfirm({ value, label }) {
427 - const idx = this.sheet.idx 448 + const { idx, mode } = this.sheet
428 const it = this.items[idx] 449 const it = this.items[idx]
429 if (!it) { this.sheet.visible = false; return } 450 if (!it) { this.sheet.visible = false; return }
430 - it.productId = value  
431 - it.productName = label || '' 451 +
  452 + if (mode === 'product') {
  453 + it.productId = value
  454 + it.productName = label || ''
  455 + } else if (mode === 'sampleOrder') {
  456 + it.sampleOrder = value
  457 + }
  458 +
432 this.$set(this.items, idx, it) 459 this.$set(this.items, idx, it)
433 this.sheet.visible = false 460 this.sheet.visible = false
434 this.emitChange() 461 this.emitChange()
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 <view v-if="mode === 'add'" class="add-list"> 16 <view v-if="mode === 'add'" class="add-list">
17 <view v-for="(item, idx) in items" :key="idx" class="block"> 17 <view v-for="(item, idx) in items" :key="idx" class="block">
18 <uni-list v-show="item.collapsed"> 18 <uni-list v-show="item.collapsed">
19 - <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.productName || '请选择产品名称'" showArrow> 19 + <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx, 'product')" :rightText="item.productName || '请选择产品名称'" showArrow>
20 <template v-slot:body> 20 <template v-slot:body>
21 <view class="item-title"><text>产品名称</text></view> 21 <view class="item-title"><text>产品名称</text></view>
22 </template> 22 </template>
@@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
33 </uni-list-item> 33 </uni-list-item>
34 </uni-list> 34 </uni-list>
35 <uni-list v-show="!item.collapsed"> 35 <uni-list v-show="!item.collapsed">
36 - <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx)" :rightText="item.productName || '请选择产品名称'" showArrow> 36 + <uni-list-item class="select-item" :class="item.productName ? 'is-filled' : 'is-empty'" clickable @click="openProductSheet(idx, 'product')" :rightText="item.productName || '请选择产品名称'" showArrow>
37 <template v-slot:body> 37 <template v-slot:body>
38 <view class="item-title"><text>产品名称</text></view> 38 <view class="item-title"><text>产品名称</text></view>
39 </template> 39 </template>
@@ -132,6 +132,12 @@ @@ -132,6 +132,12 @@
132 <uni-datetime-picker :start="minDeliveryDate" type="date" v-model="item.deliveryDate" @change="onDateChange(idx, $event)" /> 132 <uni-datetime-picker :start="minDeliveryDate" type="date" v-model="item.deliveryDate" @change="onDateChange(idx, $event)" />
133 </template> 133 </template>
134 </uni-list-item> 134 </uni-list-item>
  135 + <uni-list-item class="select-item" :class="typeof item.sampleOrder === 'boolean' ? 'is-filled' : 'is-empty'" clickable
  136 + @click="openProductSheet(idx, 'sampleOrder')" :rightText="typeof item.sampleOrder === 'boolean' ? (item.sampleOrder ? '是' : '否') : '请选择'" showArrow>
  137 + <template v-slot:body>
  138 + <view class="item-title"><text>是否为试样订单</text></view>
  139 + </template>
  140 + </uni-list-item>
135 </uni-list> 141 </uni-list>
136 <view class="block-ops"> 142 <view class="block-ops">
137 <div class="del" @click="onRemove(idx)"> 143 <div class="del" @click="onRemove(idx)">
@@ -190,6 +196,7 @@ @@ -190,6 +196,7 @@
190 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount) 196 <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount)
191 }}</text></view> 197 }}</text></view>
192 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view> 198 <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view>
  199 + <view class="row"><text class="label">是否为试样订单</text><text class="value">{{ item.sampleOrder ? '是' : '否' }}</text></view>
193 </view> 200 </view>
194 </view> 201 </view>
195 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" /> 202 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" />
@@ -212,7 +219,7 @@ export default { @@ -212,7 +219,7 @@ export default {
212 return { 219 return {
213 items: [], 220 items: [],
214 collapsedView: false, 221 collapsedView: false,
215 - sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1 } 222 + sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1, mode: 'product' }
216 } 223 }
217 }, 224 },
218 computed: { 225 computed: {
@@ -246,20 +253,20 @@ export default { @@ -246,20 +253,20 @@ export default {
246 handler(v) { 253 handler(v) {
247 // const arr = Array.isArray(v) ? v : [] 254 // const arr = Array.isArray(v) ? v : []
248 // this.items = arr.map(x => ({ ...this.defaultItem(), ...x, collapsed: true })) 255 // this.items = arr.map(x => ({ ...this.defaultItem(), ...x, collapsed: true }))
249 - this.items = v.map(x => ({ ...this.defaultItem(), ...x, collapsed: true })) 256 + this.items = v.map(x => ({ ...this.defaultItem(), ...x, sampleOrder: !!x.sampleOrder, collapsed: true }))
250 console.log('v', v) 257 console.log('v', v)
251 }, 258 },
252 deep: true 259 deep: true
253 } 260 }
254 }, 261 },
255 created() { 262 created() {
256 - const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }] 263 + const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, sampleOrder: !!v.sampleOrder, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }]
257 this.items = init 264 this.items = init
258 this.recalculateAll() 265 this.recalculateAll()
259 }, 266 },
260 methods: { 267 methods: {
261 defaultItem() { 268 defaultItem() {
262 - return { productId: '', productName: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', status: '', quantity: '', unitPrice: '', amountExcludingTax: 0, totalAmount: 0, deliveryDate: '' } 269 + return { productId: '', productName: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', status: '', quantity: '', unitPrice: '', amountExcludingTax: 0, totalAmount: 0, deliveryDate: '', sampleOrder: false }
263 }, 270 },
264 onNonNegativeInput(idx, field) { 271 onNonNegativeInput(idx, field) {
265 const it = this.items[idx] 272 const it = this.items[idx]
@@ -358,18 +365,38 @@ export default { @@ -358,18 +365,38 @@ export default {
358 const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/') 365 const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/')
359 return [t, w, l].filter(Boolean).join(' × ') 366 return [t, w, l].filter(Boolean).join(' × ')
360 }, 367 },
361 - openProductSheet(idx) {  
362 - const opts = this.selectOptions  
363 - const current = this.items[idx] && this.items[idx].productId  
364 - const match = opts.find(o => o.value === current)  
365 - this.sheet = { ...this.sheet, visible: true, title: '请选择产品', options: opts, idx, value: match ? match.value : '' } 368 + openProductSheet(idx, mode = 'product') {
  369 + let opts = []
  370 + let title = ''
  371 + let value = ''
  372 + const item = this.items[idx]
  373 +
  374 + if (mode === 'product') {
  375 + opts = this.selectOptions
  376 + const current = item && item.productId
  377 + const match = opts.find(o => o.value === current)
  378 + value = match ? match.value : ''
  379 + title = '请选择产品'
  380 + } else if (mode === 'sampleOrder') {
  381 + opts = [{ label: '是', value: true }, { label: '否', value: false }]
  382 + value = item.sampleOrder
  383 + title = '是否为试样订单'
  384 + }
  385 +
  386 + this.sheet = { ...this.sheet, visible: true, title, options: opts, idx, value, mode }
366 }, 387 },
367 onProductConfirm({ value, label }) { 388 onProductConfirm({ value, label }) {
368 - const idx = this.sheet.idx 389 + const { idx, mode } = this.sheet
369 const it = this.items[idx] 390 const it = this.items[idx]
370 if (!it) { this.sheet.visible = false; return } 391 if (!it) { this.sheet.visible = false; return }
371 - it.productId = value  
372 - it.productName = label || '' 392 +
  393 + if (mode === 'product') {
  394 + it.productId = value
  395 + it.productName = label || ''
  396 + } else if (mode === 'sampleOrder') {
  397 + it.sampleOrder = value
  398 + }
  399 +
373 this.$set(this.items, idx, it) 400 this.$set(this.items, idx, it)
374 this.sheet.visible = false 401 this.sheet.visible = false
375 this.emitChange() 402 this.emitChange()
@@ -480,8 +507,8 @@ export default { @@ -480,8 +507,8 @@ export default {
480 507
481 .opCollapse { 508 .opCollapse {
482 color: rgba(0, 0, 0, 0.6); 509 color: rgba(0, 0, 0, 0.6);
483 - width: 24rpx;  
484 - height: 24rpx; 510 + width: 32rpx;
  511 + height: 28rpx;
485 margin-right: 16rpx; 512 margin-right: 16rpx;
486 margin-top: 8rpx; 513 margin-top: 8rpx;
487 } 514 }
@@ -759,10 +759,10 @@ export default { @@ -759,10 +759,10 @@ export default {
759 759
760 .generate-btn { 760 .generate-btn {
761 margin-left: 24rpx; 761 margin-left: 24rpx;
762 - height: 64rpx;  
763 - line-height: 64rpx; 762 + height: 48rpx;
  763 + line-height: 48rpx;
764 padding: 0 24rpx; 764 padding: 0 24rpx;
765 - font-size: 28rpx; 765 + font-size: 24rpx;
766 border-radius: 8rpx; 766 border-radius: 8rpx;
767 background: $theme-primary; 767 background: $theme-primary;
768 color: #fff; 768 color: #fff;
@@ -316,10 +316,10 @@ export default { @@ -316,10 +316,10 @@ export default {
316 316
317 .generate-btn { 317 .generate-btn {
318 margin-left: 24rpx; 318 margin-left: 24rpx;
319 - height: 64rpx;  
320 - line-height: 64rpx; 319 + height: 48rpx;
  320 + line-height: 48rpx;
321 padding: 0 24rpx; 321 padding: 0 24rpx;
322 - font-size: 28rpx; 322 + font-size: 24rpx;
323 border-radius: 8rpx; 323 border-radius: 8rpx;
324 background: $theme-primary; 324 background: $theme-primary;
325 color: #fff; 325 color: #fff;
@@ -323,14 +323,14 @@ export default { @@ -323,14 +323,14 @@ export default {
323 align-items: center; 323 align-items: center;
324 324
325 .generate-btn { 325 .generate-btn {
326 - margin-left: 24rpx;  
327 - height: 64rpx;  
328 - line-height: 64rpx;  
329 - padding: 0 24rpx;  
330 - font-size: 28rpx;  
331 - border-radius: 8rpx;  
332 - background: $theme-primary;  
333 - color: #fff; 326 + margin-left: 24rpx;
  327 + height: 48rpx;
  328 + line-height: 48rpx;
  329 + padding: 0 24rpx;
  330 + font-size: 24rpx;
  331 + border-radius: 8rpx;
  332 + background: $theme-primary;
  333 + color: #fff;
334 } 334 }
335 } 335 }
336 } 336 }
1 -<template>  
2 - <view class="work-container">  
3 - <!-- 轮播图 -->  
4 - <uni-swiper-dot class="uni-swiper-dot-box" :info="data" :current="current" field="content">  
5 - <swiper class="swiper-box" :current="swiperDotIndex" @change="changeSwiper">  
6 - <swiper-item v-for="(item, index) in data" :key="index">  
7 - <view class="swiper-item" @click="clickBannerItem(item)">  
8 - <image :src="item.image" mode="aspectFill" :draggable="false" />  
9 - </view>  
10 - </swiper-item>  
11 - </swiper>  
12 - </uni-swiper-dot>  
13 -  
14 - <!-- 宫格组件 -->  
15 - <uni-section title="商品管理" type="line">  
16 - <HR style="border:1 dashed #eeeeff" width="100%" color='#eeeeff' SIZE='1' />  
17 - <view class="grid-body">  
18 - <uni-grid :column="4" :showBorder="false" @change="changeGrid">  
19 -  
20 - <uni-grid-item :index=1>  
21 - <view class="grid-item-box">  
22 - <!-- <uni-icons color="#000" type="gift" size="30"></uni-icons> -->  
23 - <view class="cuIcon-goods text-yellow icon"></view>  
24 - <text class="text">商品管理</text>  
25 - </view>  
26 - </uni-grid-item>  
27 - <uni-grid-item :index=2>  
28 - <view class="grid-item-box">  
29 - <!-- <uni-icons color="#000" type="list" size="30"></uni-icons> -->  
30 - <view class="cuIcon-list text-yellow icon"></view>  
31 - <text class="text">商品类目</text>  
32 - </view>  
33 - </uni-grid-item>  
34 - <uni-grid-item :index=3>  
35 - <view class="grid-item-box">  
36 - <!-- <uni-icons color="#000" type="color" size="30"></uni-icons> -->  
37 - <view class="cuIcon-info text-yellow icon"></view>  
38 - <text class="text">商品属性</text>  
39 - </view>  
40 - </uni-grid-item>  
41 - <uni-grid-item :index=4>  
42 - <view class="grid-item-box">  
43 - <view class="cuIcon-brand text-yellow icon"></view>  
44 - <text class="text">商品品牌</text>  
45 - </view>  
46 - </uni-grid-item>  
47 - </uni-grid>  
48 - </view>  
49 - </uni-section>  
50 - <uni-section title="基本资料" type="line">  
51 - <HR style="border:1 dashed #eeeeff" width="100%" color='#eeeeff' SIZE='1' />  
52 - <view class="grid-body">  
53 - <uni-grid :column="4" :showBorder="false" @change="changeGrid">  
54 - <uni-grid-item :index=5>  
55 - <view class="grid-item-box">  
56 - <view class="cuIcon-friend text-pink icon"></view>  
57 - <text class="text">客户管理</text>  
58 - </view>  
59 - </uni-grid-item>  
60 - <uni-grid-item :index=6>  
61 - <view class="grid-item-box">  
62 - <view class="cuIcon-friendfavor text-pink icon"></view>  
63 - <text class="text">供应商管理</text>  
64 - </view>  
65 - </uni-grid-item>  
66 - <uni-grid-item :index=7>  
67 - <view class="grid-item-box">  
68 - <view class="cuIcon-friendfamous text-pink icon"></view>  
69 - <text class="text">会员管理</text>  
70 - </view>  
71 - </uni-grid-item>  
72 - <uni-grid-item :index=8>  
73 - <view class="grid-item-box">  
74 - <view class="cuIcon-home text-pink icon"></view>  
75 - <text class="text">仓库管理</text>  
76 - </view>  
77 - </uni-grid-item>  
78 - <uni-grid-item :index=9>  
79 - <view class="grid-item-box">  
80 - <!-- <uni-icons color="#007AFF" type="shop" size="30"></uni-icons> -->  
81 - <view class="cuIcon-shop text-pink icon"></view>  
82 - <text class="text">门店管理</text>  
83 - </view>  
84 - </uni-grid-item>  
85 - <uni-grid-item :index=10>  
86 - <view class="grid-item-box">  
87 - <!-- <uni-icons color="#007AFF" type="wallet" size="30"></uni-icons> -->  
88 - <view class="cuIcon-sponsor text-pink icon"></view>  
89 - <text class="text">支付管理</text>  
90 - </view>  
91 - </uni-grid-item>  
92 - <uni-grid-item :index=11>  
93 - <view class="grid-item-box">  
94 - <!-- <uni-icons color="#007AFF" type="map-pin-ellipse" size="30"></uni-icons> -->  
95 - <view class="cuIcon-addressbook text-pink icon"></view>  
96 - <text class="text">地址库</text>  
97 - </view>  
98 - </uni-grid-item>  
99 - <uni-grid-item :index=12>  
100 - <view class="grid-item-box">  
101 - <view class="cuIcon-deliver text-pink icon"></view>  
102 - <text class="text">物流管理</text>  
103 - </view>  
104 - </uni-grid-item>  
105 -  
106 - </uni-grid>  
107 - </view>  
108 - </uni-section>  
109 - <view>  
110 - <uni-popup ref="alertDialog" type="dialog">  
111 - <uni-popup-dialog type="info" cancelText="关闭" confirmText="确定" title="专业版源代码" content="专业版源代码">  
112 - <view>  
113 - <image src="../../static/images/wx.jpg" style="width: 250px;height: 250px;"></image>  
114 - </view>  
115 - </uni-popup-dialog>  
116 - </uni-popup>  
117 - </view>  
118 - </view>  
119 -</template>  
120 -  
121 -<script>  
122 - export default {  
123 - data() {  
124 - return {  
125 - current: 0,  
126 - swiperDotIndex: 0,  
127 - data: [{  
128 - image: 'http://xy.wecando21cn.com/static/images/banner/banner01.jpg'  
129 - },  
130 - {  
131 - image: 'http://xy.wecando21cn.com/static/images/banner/banner02.jpg'  
132 - },  
133 - {  
134 - image: 'http://xy.wecando21cn.com/static/images/banner/banner03.jpg'  
135 - }  
136 - ],  
137 - }  
138 - },  
139 - methods: {  
140 - clickBannerItem(item) {  
141 - console.info(item)  
142 - },  
143 - changeSwiper(e) {  
144 - this.current = e.detail.current  
145 - },  
146 - changeGrid(e) {  
147 - this.$refs.alertDialog.open('center');  
148 -  
149 - }  
150 - }  
151 - }  
152 -</script>  
153 -  
154 -<style lang="scss">  
155 - /* #ifndef APP-NVUE */  
156 - page {  
157 - display: flex;  
158 - flex-direction: column;  
159 - box-sizing: border-box;  
160 - background-color: #fff;  
161 - min-height: 100%;  
162 - height: auto;  
163 - }  
164 -  
165 - view {  
166 - font-size: 14px;  
167 - line-height: inherit;  
168 - }  
169 -  
170 - .uni-icons {  
171 - color: #007AFF;  
172 - }  
173 -  
174 - /* #endif */  
175 -  
176 - .text {  
177 - text-align: center;  
178 - font-size: 26rpx;  
179 - margin-top: 10rpx;  
180 - }  
181 -  
182 - .grid-item-box {  
183 - flex: 1;  
184 - /* #ifndef APP-NVUE */  
185 - display: flex;  
186 - /* #endif */  
187 - flex-direction: column;  
188 - align-items: center;  
189 - justify-content: center;  
190 - padding: 15px 0;  
191 - }  
192 -  
193 - .uni-margin-wrap {  
194 - width: 690rpx;  
195 - width: 100%;  
196 - ;  
197 - }  
198 -  
199 - .swiper {  
200 - height: 300rpx;  
201 - }  
202 -  
203 - .swiper-box {  
204 - height: 150px;  
205 - }  
206 -  
207 - .swiper-item {  
208 - /* #ifndef APP-NVUE */  
209 - display: flex;  
210 - /* #endif */  
211 - flex-direction: column;  
212 - justify-content: center;  
213 - align-items: center;  
214 - color: #fff;  
215 - height: 300rpx;  
216 - line-height: 300rpx;  
217 - }  
218 -  
219 - @media screen and (min-width: 500px) {  
220 - .uni-swiper-dot-box {  
221 - width: 400px;  
222 - /* #ifndef APP-NVUE */  
223 - margin: 0 auto;  
224 - /* #endif */  
225 - margin-top: 8px;  
226 - }  
227 -  
228 - .image {  
229 - width: 100%;  
230 - }  
231 - }  
232 -  
233 - // .text {  
234 - // display: block;  
235 - // font-size: 13px;  
236 - // margin: 8px 0px;  
237 - // }  
238 - .icon {  
239 - font-size: 28px;  
240 - }  
241 -  
242 - .text {  
243 - text-align: center;  
244 - font-size: 26rpx;  
245 - margin-top: 10rpx;  
246 - }  
247 -</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.customerName }}</text>
  7 + <view class="row"><text class="label">订单编号</text><text class="value">{{ form.orderNo }}</text></view>
  8 + <view class="row"><text class="label">生产厂</text><text class="value">{{ form.workshopName }}</text></view>
  9 + </view>
  10 +
  11 + <!-- 产品 -->
  12 + <view class="section2">
  13 + <Product mode="view" :list="form.detailList" />
  14 + </view>
  15 +
  16 + </view>
  17 + </scroll-view>
  18 + <!-- <detail-buttons :buttons="displayButtons" @click="handleButtonClick" /> -->
  19 + </view>
  20 +</template>
  21 +
  22 +<script>
  23 +import { getDetailApi } from '@/api/feedback_form.js'
  24 +import Product from './product.vue'
  25 +import DetailButtons from '@/components/detail-buttons/index.vue'
  26 +import { downloadFile } from '@/utils/downloadFile.js'
  27 +import {
  28 + getDicByCodes
  29 +} from '@/utils/dic'
  30 +import {
  31 + getDicName
  32 +} from '@/utils/dic.js'
  33 +
  34 +export default {
  35 + name: 'FeedbackFormDetail',
  36 + components: { Product, DetailButtons },
  37 + data() {
  38 + return {
  39 + form: {},
  40 + buttons: [
  41 + // { text: '编辑', visible: true, variant: 'outline', event: 'edit' },
  42 + // { text: '审核详情', visible: true, variant: 'outline', event: 'auditDetail' },
  43 + // { text: '审核', visible: true, variant: 'primary', event: 'audit' },
  44 + ],
  45 + dicOptions: {
  46 + SAMPLE_RESULT: [],
  47 + SAMPLE_RESULT_SUB: []
  48 + },
  49 + sampleResultLocal: [],
  50 + sampleResultSubLocal: []
  51 + }
  52 + },
  53 + computed: {
  54 + // statusFlags() {
  55 + // const m = this.form || {}
  56 + // const e = String(m.status || '')
  57 + // return {
  58 + // // 跟踪单编辑:1:审核状态为空、已驳回 2:showAudit为true 3:需要加角色权限
  59 + // canEdit: (!e || e === 'REFUSE') && m.showAudit || false,
  60 + // canAudit: e === 'AUDIT' && m.showExamine || false,
  61 + // canAuditDetail: !!e || false,
  62 + // }
  63 + // },
  64 + // displayButtons() {
  65 + // const f = this.statusFlags;
  66 + // console.log('displayButtons_f', f)
  67 + // return [
  68 + // { ...this.buttons[0], visible: f.canEdit && this.$auth.hasPermi('sample-order:follow-up-form:modify') },
  69 + // { ...this.buttons[1], visible: f.canAuditDetail && this.$auth.hasPermi('sample-order:follow-up-form:review') },
  70 + // { ...this.buttons[2], visible: f.canAudit && this.$auth.hasPermi('sample-order:follow-up-form:approve') },
  71 + // ]
  72 + // }
  73 + },
  74 + onLoad(query) {
  75 + const id = (query && (query.id || query.code)) || ''
  76 + if (id) {
  77 + this.loadDetail(id)
  78 + // this.loadAllDicData()
  79 + }
  80 + },
  81 + methods: {
  82 + async loadDetail(id) {
  83 + try {
  84 + const res = await getDetailApi(id)
  85 + this.form = res.data || {}
  86 + } catch (e) {
  87 + this.form = {}
  88 + }
  89 + },
  90 + handleButtonClick(btn) {
  91 + if (!btn || btn.disabled) return
  92 + const map = {
  93 + edit: () => this.onEdit(),
  94 + auditDetail: () => this.onAuditDetail(),
  95 + audit: () => this.onAudit(),
  96 + }
  97 + const fn = map[btn.event]
  98 + if (typeof fn === 'function') fn()
  99 + },
  100 + onEdit() {
  101 + const id = this.form.id || this.form.code
  102 + if (id) uni.navigateTo({ url: `/pages/follow_up_form/modify?id=${id}` })
  103 + },
  104 + onAuditDetail() {
  105 + uni.setStorageSync('sourceBusinessId', this.form.id)
  106 + uni.navigateTo({ url: '/pages/flow/audit_detail' })
  107 + },
  108 + onAudit() {
  109 + uni.setStorageSync('sourceBusinessId', this.form.id)
  110 + uni.navigateTo({ url: '/pages/flow/audit' })
  111 + },
  112 + downloadFile,
  113 + getDicName,
  114 + loadAllDicData() {
  115 + const dicCodes = ['SAMPLE_RESULT', 'SAMPLE_RESULT_SUB']
  116 + return getDicByCodes(dicCodes).then(results => {
  117 + this.dicOptions.SAMPLE_RESULT = results.SAMPLE_RESULT.data || []
  118 + this.dicOptions.SAMPLE_RESULT_SUB = results.SAMPLE_RESULT_SUB.data || []
  119 + this.sampleResultLocal = (this.dicOptions.SAMPLE_RESULT || []).map(it => ({
  120 + value: it.code,
  121 + text: it.name
  122 + }))
  123 + this.sampleResultSubLocal = (this.dicOptions.SAMPLE_RESULT_SUB || []).map(it => ({
  124 + value: it.code,
  125 + text: it.name
  126 + }))
  127 + }).catch(() => {
  128 + this.dicOptions = {
  129 + SAMPLE_RESULT: [],
  130 + SAMPLE_RESULT_SUB: []
  131 + }
  132 + this.sampleResultLocal = []
  133 + this.sampleResultSubLocal = []
  134 + })
  135 + },
  136 + }
  137 +}
  138 +</script>
  139 +
  140 +<style lang="scss" scoped>
  141 +.page {
  142 + display: flex;
  143 + flex-direction: column;
  144 + height: 100vh;
  145 +}
  146 +
  147 +.scroll {
  148 + flex: 1;
  149 + background: #f3f3f3;
  150 +}
  151 +
  152 +.detail-page {
  153 + padding-bottom: 20rpx;
  154 +}
  155 +
  156 +.section {
  157 + padding: 32rpx;
  158 + background: #fff;
  159 + margin-bottom: 20rpx;
  160 + position: relative;
  161 +
  162 + .status {
  163 + position: absolute;
  164 + top: 16rpx;
  165 + right: 52rpx;
  166 + width: 180rpx;
  167 + height: 146rpx;
  168 + background-repeat: no-repeat;
  169 + background-size: 100% 100%;
  170 + background-position: center;
  171 +
  172 + &_AUDIT {
  173 + background-image: url('~@/static/images/dev_manage/status_1.png');
  174 + }
  175 +
  176 + &_PASS {
  177 + background-image: url('~@/static/images/dev_manage/status_2.png');
  178 + }
  179 +
  180 + &_REFUSE {
  181 + background-image: url('~@/static/images/dev_manage/status_3.png');
  182 + }
  183 +
  184 + &_CANCEL {
  185 + background-image: url('~@/static/images/dev_manage/status_4.png');
  186 + }
  187 +
  188 + }
  189 +}
  190 +
  191 +.row {
  192 + display: flex;
  193 + margin-bottom: 28rpx;
  194 +
  195 + &:last-child {
  196 + margin-bottom: 0;
  197 + }
  198 +
  199 + &.company {
  200 + font-size: 36rpx;
  201 + font-weight: 600;
  202 + color: rgba(0, 0, 0, 0.9);
  203 + padding-top: 10rpx;
  204 + margin-bottom: 32rpx;
  205 + line-height: 50rpx;
  206 + }
  207 +
  208 + .label {
  209 + max-width: 400rpx;
  210 + margin-right: 20rpx;
  211 + line-height: 32rpx;
  212 + font-size: 28rpx;
  213 + color: rgba(0, 0, 0, 0.6);
  214 + }
  215 +
  216 + .value {
  217 + flex: 1;
  218 + line-height: 32rpx;
  219 + font-size: 28rpx;
  220 + color: rgba(0, 0, 0, 0.9);
  221 + text-align: right;
  222 + word-break: break-all;
  223 +
  224 + &.act {
  225 + color: $theme-primary;
  226 + }
  227 +
  228 + }
  229 +}
  230 +
  231 +.title-header {
  232 + background-color: #fff;
  233 + display: flex;
  234 + align-items: center;
  235 + padding: 32rpx 32rpx 22rpx;
  236 + border-bottom: 1rpx dashed #f0f0f0;
  237 +
  238 + &_icon {
  239 + width: 32rpx;
  240 + height: 28rpx;
  241 + margin-right: 16rpx;
  242 + }
  243 +
  244 + span {
  245 + color: rgba(0, 0, 0, 0.9);
  246 + font-size: 32rpx;
  247 + line-height: 44rpx;
  248 + font-weight: 600;
  249 + }
  250 +}
  251 +
  252 +.section2 {
  253 + background: #f1f1f1;
  254 + margin-bottom: 20rpx;
  255 +}
  256 +
  257 +
  258 +.section3 {
  259 + padding: 0 32rpx;
  260 + background-color: #fff;
  261 + margin: 20rpx 0;
  262 +}
  263 +
  264 +.view-total {
  265 + padding-bottom: 20rpx;
  266 +
  267 + .head {
  268 + font-size: 32rpx;
  269 + font-weight: 600;
  270 + line-height: 50rpx;
  271 + color: rgba(0, 0, 0, 0.9);
  272 + padding-bottom: 16rpx;
  273 + margin-bottom: 24rpx;
  274 + border-bottom: 1px dashed #E7E7E7;
  275 + }
  276 +
  277 + .row {
  278 + display: flex;
  279 + margin-bottom: 24rpx;
  280 + line-height: 32rpx;
  281 +
  282 + .row2 {
  283 + width: 50%;
  284 + }
  285 +
  286 + .label {
  287 + width: 180rpx;
  288 + margin-right: 14rpx;
  289 + color: rgba(0, 0, 0, 0.6);
  290 + font-size: 28rpx;
  291 + }
  292 +
  293 + .value {
  294 + flex: 1;
  295 + color: rgba(0, 0, 0, 0.9);
  296 + font-size: 28rpx;
  297 + white-space: pre-wrap;
  298 + word-break: break-all;
  299 + }
  300 + }
  301 +}
  302 +</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.customerName }}</text>
  23 + <!-- <text :class="['status', `status_${item.status}`]">{{ filterStatus(item.status) }}</text> -->
  24 + </view>
  25 + <view class="info-row">
  26 + <text>订单编号</text><text>{{ item.orderNo || '-' }}</text>
  27 + </view>
  28 + <view class="info-row">
  29 + <text>生产厂</text><text>{{ item.workshopName || '-' }}</text>
  30 + </view>
  31 + </view>
  32 + </template>
  33 + </card-list>
  34 + </view>
  35 +
  36 +
  37 +
  38 + <!-- 筛选弹框 -->
  39 + <filter-modal :visible.sync="filterVisible" :value.sync="filterForm" title="筛选" @reset="onFilterReset"
  40 + @confirm="onFilterConfirm">
  41 + <template v-slot="{ model }">
  42 + <view class="filter-form">
  43 + <view class="form-item">
  44 + <view class="label">生产厂</view>
  45 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  46 + v-model="model.workshopId" @change="onWorkshopChange" :localdata="workshopOptions" />
  47 + </view>
  48 + <!-- <view class="form-item">
  49 + <view class="label">审核状态</view>
  50 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  51 + v-model="model.status" @change="onStatusChange" :localdata="statusLocal" />
  52 + </view> -->
  53 + <!-- <view class="form-item">
  54 + <view class="label">试样种类</view>
  55 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  56 + v-model="model.sampleType" @change="onSampleTypeChange" :localdata="sampleTypeLocal" />
  57 + </view>
  58 + <view class="form-item">
  59 + <view class="label">客户类型</view>
  60 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  61 + v-model="model.customerType" @change="onEnterpriseTypeChange" :localdata="enterpriseTypeLocal" />
  62 + </view> -->
  63 + </view>
  64 + </template>
  65 + </filter-modal>
  66 + </view>
  67 +</template>
  68 +
  69 +<script>
  70 +import CardList from '@/components/card/index.vue'
  71 +import FilterModal from '@/components/filter/index.vue'
  72 +import { workshopQueryApi } from '@/api/devManage.js'
  73 +import SingleSelectSheet from '@/components/single-select/index.vue'
  74 +import {
  75 + queryApi
  76 +} from '@/api/feedback_form.js'
  77 +import {
  78 + getDicByCodes
  79 +} from '@/utils/dic'
  80 +
  81 +export default {
  82 + components: {
  83 + CardList,
  84 + FilterModal,
  85 + SingleSelectSheet
  86 + },
  87 + data() {
  88 + return {
  89 + searchKeyword: '',
  90 + searchKeywordDebounced: '',
  91 + tabs: [],
  92 + // 给到 card 的筛选值
  93 + query: {
  94 + status: '',
  95 + workshopId: '',
  96 + },
  97 + extraParams: {},
  98 +
  99 + // 批量选择
  100 + rowKey: 'id',
  101 + currentItems: [],
  102 +
  103 + // 筛选弹框
  104 + filterVisible: false,
  105 + filterForm: {
  106 + status: '',
  107 + workshopId: '',
  108 + },
  109 + dicOptions: {
  110 + AUDIT_STATUS: [], // 审核
  111 + },
  112 + statusLocal: [],
  113 + workshopOptions: [],
  114 + }
  115 + },
  116 + computed: {
  117 + extraCombined() {
  118 + return {
  119 + searchKey: this.searchKeywordDebounced || undefined
  120 + }
  121 + }
  122 + },
  123 + watch: {
  124 + extraCombined: {
  125 + deep: true,
  126 + handler(v) {
  127 + this.extraParams = v
  128 + },
  129 + immediate: true
  130 + },
  131 +
  132 + },
  133 + created() {
  134 + // this.loadAllDicData()
  135 + this.loadWorkshopOptions()
  136 + },
  137 + onLoad() { },
  138 + // 页面触底兜底:当页面自身滚动到底部时,转调卡片组件加载更多
  139 + onReachBottom() {
  140 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) {
  141 + this.$refs.cardRef.onLoadMore()
  142 + }
  143 + },
  144 + beforeDestroy() {
  145 + if (this.searchDebounceTimer) {
  146 + clearTimeout(this.searchDebounceTimer)
  147 + this.searchDebounceTimer = null
  148 + }
  149 + },
  150 + methods: {
  151 + async loadWorkshopOptions() {
  152 + try {
  153 + const res = await workshopQueryApi({ pageIndex: 1, pageSize: 9999 })
  154 + const list = (res && res.data && res.data.datas) || []
  155 + this.workshopOptions = list.map(it => ({ text: it.name || it.workshopName || '', value: it.id || it.workshopId || '' }))
  156 + } catch (e) {
  157 + this.workshopOptions = []
  158 + }
  159 + },
  160 + onCardLoaded({
  161 + items
  162 + }) {
  163 + this.currentItems = items
  164 + },
  165 + onCardError() {
  166 + uni.showToast({
  167 + title: '列表加载失败',
  168 + icon: 'none'
  169 + })
  170 + },
  171 + // 输入实时搜索:1200ms 防抖,仅在停止输入超过阈值后刷新
  172 + onSearchInput(val) {
  173 + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer)
  174 + this.searchDebounceTimer = setTimeout(() => {
  175 + this.searchKeywordDebounced = this.searchKeyword
  176 + this.searchDebounceTimer = null
  177 + }, 1200)
  178 + },
  179 + // uni-search-bar 确认搜索:更新关键字并触发 CardList 刷新
  180 + search(e) {
  181 + const val = e && e.value != null ? e.value : this.searchKeyword
  182 + this.searchKeyword = val
  183 + this.searchKeywordDebounced = val
  184 + },
  185 + onAdd() {
  186 + uni.navigateTo({
  187 + url: '/pages/follow_up_form/add'
  188 + })
  189 + },
  190 + openFilter() {
  191 + this.filterVisible = true
  192 + },
  193 + onFilterReset(payload) {
  194 + this.filterForm = payload
  195 + },
  196 + onFilterConfirm(payload) {
  197 + if ((payload.status === '' || payload.status == null) && this.filterForm.status !== '') {
  198 + payload.status = this.filterForm.status
  199 + }
  200 + this.query = {
  201 + ...payload
  202 + }
  203 + },
  204 + onStatusChange(e) {
  205 + const raw = e && e.detail && e.detail.value !== undefined ?
  206 + e.detail.value :
  207 + (e && e.value !== undefined ? e.value : '')
  208 + this.filterForm.status = raw
  209 + },
  210 +
  211 + onSampleTypeChange(e) {
  212 + const raw = e && e.detail && e.detail.value !== undefined ?
  213 + e.detail.value :
  214 + (e && e.value !== undefined ? e.value : '')
  215 + this.filterForm.sampleType = raw
  216 + },
  217 +
  218 + onEnterpriseTypeChange(e) {
  219 + const raw = e && e.detail && e.detail.value !== undefined ?
  220 + e.detail.value :
  221 + (e && e.value !== undefined ? e.value : '')
  222 + this.filterForm.customerType = raw
  223 + },
  224 +
  225 + // 列表接口(真实请求)
  226 + fetchList({
  227 + pageIndex,
  228 + pageSize,
  229 + query,
  230 + extra
  231 + }) {
  232 + const params = {
  233 + pageIndex,
  234 + pageSize,
  235 + ...extra,
  236 + ...query
  237 + }
  238 + if (this.searchKeywordDebounced) {
  239 + params.searchKey = this.searchKeywordDebounced
  240 + }
  241 + return queryApi(params)
  242 + .then(res => {
  243 + const _data = res.data || {};
  244 + const records = _data.datas || [];
  245 + const totalCount = _data.totalCount || 0;
  246 + const hasNext = _data.hasNext || false
  247 + return {
  248 + records,
  249 + totalCount,
  250 + hasNext
  251 + }
  252 + })
  253 + .catch(err => {
  254 + console.error('fetchList error', err)
  255 + this.onCardError()
  256 + return {
  257 + records: [],
  258 + totalCount: 0,
  259 + hasNext: false
  260 + }
  261 + })
  262 + },
  263 + loadAllDicData() {
  264 + const dicCodes = ['AUDIT_STATUS']
  265 + return getDicByCodes(dicCodes).then(results => {
  266 + this.dicOptions.AUDIT_STATUS = results.AUDIT_STATUS.data || []
  267 + this.statusLocal = (this.dicOptions.AUDIT_STATUS || []).map(it => ({
  268 + value: it.code,
  269 + text: it.name
  270 + }))
  271 + }).catch(() => {
  272 + this.dicOptions = {
  273 + AUDIT_STATUS: [],
  274 + }
  275 + this.statusLocal = []
  276 + })
  277 + },
  278 + onCardClick(item) {
  279 + const id = (item && (item.id || item.code)) || ''
  280 + if (!id) return
  281 + const query = '?id=' + encodeURIComponent(id)
  282 + uni.navigateTo({
  283 + url: '/pages/feedback_form/detail' + query
  284 + })
  285 + },
  286 + onWorkshopChange(e) {
  287 + const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ? e.value : '')
  288 + this.filterForm.workshopId = raw
  289 + const match = (this.workshopOptions || []).find(o => String(o.value) === String(raw))
  290 + this.filterForm.workshopIdName = match ? (match.text || '') : ''
  291 + },
  292 + filterStatus(status) {
  293 + const _item = this.statusLocal.filter(item => item.value === status)[0] || {};
  294 + return _item.text || '';
  295 + },
  296 + }
  297 +}
  298 +</script>
  299 +
  300 +<style lang="scss" scoped>
  301 +.page {
  302 + display: flex;
  303 + flex-direction: column;
  304 + height: 100vh;
  305 +}
  306 +
  307 +.dev-list-fixed {
  308 + position: fixed;
  309 + top: 96rpx;
  310 + left: 0;
  311 + right: 0;
  312 + z-index: 2;
  313 + background: #fff;
  314 +
  315 + .search-row {
  316 + display: flex;
  317 + align-items: center;
  318 + padding: 16rpx 32rpx;
  319 +
  320 + .uni-searchbar {
  321 + padding: 0;
  322 + flex: 1;
  323 + }
  324 +
  325 + .tool-icons {
  326 + display: flex;
  327 +
  328 + .tool-icon {
  329 + width: 48rpx;
  330 + height: 48rpx;
  331 + display: block;
  332 + margin-left: 32rpx;
  333 + }
  334 + }
  335 + }
  336 +
  337 +}
  338 +
  339 +/* 仅当前页覆盖 uni-search-bar 盒子高度 */
  340 +::v-deep .uni-searchbar__box {
  341 + height: 80rpx !important;
  342 + justify-content: start;
  343 +
  344 + .uni-searchbar__box-search-input {
  345 + font-size: 32rpx !important;
  346 + }
  347 +}
  348 +
  349 +.list-box {
  350 + flex: 1;
  351 + padding-top: 140rpx;
  352 +
  353 + &.pad-batch {
  354 + padding-bottom: 144rpx;
  355 + }
  356 +
  357 + .card {
  358 + position: relative;
  359 + }
  360 +
  361 + .card-header {
  362 + margin-bottom: 28rpx;
  363 + position: relative;
  364 +
  365 + .title {
  366 + font-size: 36rpx;
  367 + font-weight: 600;
  368 + line-height: 50rpx;
  369 + color: rgba(0, 0, 0, 0.9);
  370 + width: 578rpx;
  371 + }
  372 +
  373 + .status {
  374 + font-weight: 600;
  375 + position: absolute;
  376 + top: -32rpx;
  377 + right: -12rpx;
  378 + height: 48rpx;
  379 + line-height: 48rpx;
  380 + color: #fff;
  381 + font-size: 24rpx;
  382 + padding: 0 14rpx;
  383 + border-radius: 6rpx;
  384 +
  385 + // 审核中
  386 + &.status_AUDIT {
  387 + background: $theme-primary;
  388 + }
  389 +
  390 + // 审核通过
  391 + &.status_PASS {
  392 + background: #2BA471;
  393 + }
  394 +
  395 + // 已驳回
  396 + &.status_REFUSE {
  397 + background: #d54941;
  398 + }
  399 +
  400 + // 已取消
  401 + &.status_CANCEL {
  402 + background: #e7e7e7;
  403 + color: rgba(0, 0, 0, 0.6);
  404 + }
  405 +
  406 + }
  407 +
  408 + }
  409 +
  410 + .info-row {
  411 + display: flex;
  412 + align-items: center;
  413 + color: rgba(0, 0, 0, 0.6);
  414 + font-size: 28rpx;
  415 + margin-bottom: 24rpx;
  416 +
  417 + &:last-child {
  418 + margin-bottom: 0;
  419 + }
  420 +
  421 + text {
  422 + width: 60%;
  423 + line-height: 32rpx;
  424 +
  425 + &:last-child {
  426 + color: rgba(0, 0, 0, 0.9);
  427 + width: 40%;
  428 + }
  429 +
  430 + &.category {
  431 + display: inline-block;
  432 + padding: 4rpx 12rpx;
  433 + border-radius: 6rpx;
  434 + font-size: 24rpx;
  435 + width: auto;
  436 +
  437 + &.category_A {
  438 + background: #FFF0ED;
  439 + color: #D54941;
  440 + }
  441 +
  442 + &.category_B {
  443 + background: #FFF1E9;
  444 + color: #E37318;
  445 + }
  446 +
  447 + &.category_C {
  448 + background: #F2F3FF;
  449 + color: $theme-primary;
  450 + }
  451 +
  452 + &.category_D {
  453 + background: #E3F9E9;
  454 + color: #2BA471;
  455 + }
  456 + }
  457 + }
  458 +
  459 + }
  460 +}
  461 +
  462 +.filter-form {
  463 + .form-item {
  464 + margin-bottom: 24rpx;
  465 + }
  466 +
  467 + .label {
  468 + margin-bottom: 20rpx;
  469 + color: rgba(0, 0, 0, 0.9);
  470 + height: 44rpx;
  471 + line-height: 44rpx;
  472 + font-size: 30rpx;
  473 + }
  474 +
  475 + .uni-easyinput {
  476 + border: 1rpx solid #f3f3f3;
  477 + }
  478 +
  479 +}
  480 +
  481 +/* 深度覆盖 uni-data-checkbox(mode=tag)内部的 tag 展示与间距 */
  482 +::v-deep .filter-form .uni-data-checklist .checklist-group {
  483 + .checklist-box {
  484 + &.is--tag {
  485 + width: 212rpx;
  486 + margin-top: 0;
  487 + margin-bottom: 24rpx;
  488 + margin-right: 24rpx;
  489 + height: 80rpx;
  490 + padding: 0 20rpx;
  491 + border-radius: 12rpx;
  492 + background-color: #f3f3f3;
  493 + border-color: #f3f3f3;
  494 +
  495 + &:nth-child(3n) {
  496 + margin-right: 0;
  497 + }
  498 +
  499 + .checklist-content {
  500 + display: flex;
  501 + justify-content: center;
  502 + }
  503 +
  504 + .checklist-text {
  505 + color: rgba(0, 0, 0, 0.9);
  506 + font-size: 28rpx;
  507 + text-align: center;
  508 + }
  509 + }
  510 +
  511 + &.is-checked {
  512 + background-color: $theme-primary-plain-bg !important;
  513 + border-color: $theme-primary-plain-bg !important;
  514 +
  515 + .checklist-text {
  516 + color: $theme-primary !important;
  517 + }
  518 + }
  519 + }
  520 +
  521 +}
  522 +</style>
  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 + <view class="row"><text class="label">牌号</text><text class="value">{{ item.brand }}</text></view>
  21 + <!-- 厚(公差) * 宽(公差) * 长(公差) -->
  22 + <view class="row row-spec"><text class="label">规格(mm)</text>
  23 + <view class="value value-spec">
  24 + <view v-if="item.thickness" class="value-spec_val">{{ item.thickness }}</view>
  25 + <view v-if="item.thickness" class="value-spec_box">
  26 + <view v-if="item.thicknessTolPos" class="value-spec_box_1">{{ item.thicknessTolPos > 0 ? '+' + item.thicknessTolPos : item.thicknessTolPos }}
  27 + </view>
  28 + <view v-if="item.thicknessTolNeg" class="value-spec_box_2">{{ item.thicknessTolNeg > 0 ? '+' + item.thicknessTolNeg : item.thicknessTolNeg }}
  29 + </view>
  30 + </view>
  31 + <view v-if="item.width" class="value-spec_val p12">*</view>
  32 + <view v-if="item.width" class="value-spec_val">{{ item.width }}</view>
  33 + <view v-if="item.width" class="value-spec_box">
  34 + <view v-if="item.widthTolPos" class="value-spec_box_1">{{ item.widthTolPos > 0 ? '+' +
  35 + item.widthTolPos : item.widthTolPos }}</view>
  36 + <view v-if="item.widthTolNeg" class="value-spec_box_2">{{ item.widthTolNeg > 0 ? '+' +
  37 + item.widthTolNeg : item.widthTolNeg }}</view>
  38 + </view>
  39 + <view v-if="item.length" class="value-spec_val p12">*</view>
  40 + <view v-if="item.length" class="value-spec_val">{{ item.length }}</view>
  41 + <view v-if="item.length" class="value-spec_box">
  42 + <view v-if="item.lengthTolPos" class="value-spec_box_1">{{ item.lengthTolPos > 0 ? '+' +
  43 + item.lengthTolPos : item.lengthTolPos }}</view>
  44 + <view v-if="item.lengthTolNeg" class="value-spec_box_2">{{ item.lengthTolNeg > 0 ? '+' +
  45 + item.lengthTolNeg : item.lengthTolNeg }}</view>
  46 + </view>
  47 + </view>
  48 + </view>
  49 + <view class="row"><text class="label">状态</text><text class="value">{{ item.status }}</text></view>
  50 + <view v-show="!item.collapsed">
  51 +
  52 + <view class="row" :class="{ 'noneStyle': !item.showSalesPrice }"><text
  53 + class="label">数量kg</text><text class="value">{{ item.quantity }}</text>
  54 + </view>
  55 +
  56 + <uni-list class="edit-list">
  57 + <uni-list-item class="select-item"
  58 + :class="item.provideSamplesName ? 'is-filled' : 'is-empty'" clickable
  59 + @click="openProductSheet(idx, 'provideSamples')"
  60 + :rightText="item.provideSamplesName || '请选择是否提供样品'" showArrow>
  61 + <template v-slot:body>
  62 + <view class="item-title"><text>是否提供样品</text></view>
  63 + </template>
  64 + </uni-list-item>
  65 + <uni-list-item class="select-item"
  66 + :class="item.clearParametersName ? 'is-filled' : 'is-empty'" clickable
  67 + @click="openProductSheet(idx, 'clearParameters')"
  68 + :rightText="item.clearParametersName || '请选择是否提供明确参数'" showArrow>
  69 + <template v-slot:body>
  70 + <view class="item-title"><text>是否提供明确参数</text></view>
  71 + </template>
  72 + </uni-list-item>
  73 + </uni-list>
  74 + </view>
  75 +
  76 + <view class="block-ops">
  77 + <div class="toggle" @click="toggleItem(idx)">
  78 + <image :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'"
  79 + class="icon" />
  80 + {{ item.collapsed ? '展开' : '收起' }}
  81 + </div>
  82 + </view>
  83 + </view>
  84 + </view>
  85 +
  86 + <view v-else-if="mode === 'view'" class="view-list" v-show="!collapsedView">
  87 + <view v-for="(item, idx) in items" :key="'v-' + idx" class="card">
  88 + <view class="row"><text class="label">牌号</text><text class="value">{{ item.brand }}</text></view>
  89 + <!-- 厚(公差) * 宽(公差) * 长(公差) -->
  90 + <view class="row row-spec"><text class="label">规格(mm)</text>
  91 + <view class="value value-spec">
  92 + <view v-if="item.thickness" class="value-spec_val">{{ item.thickness }}</view>
  93 + <view v-if="item.thickness" class="value-spec_box">
  94 + <view v-if="item.thicknessTolPos" class="value-spec_box_1">{{ item.thicknessTolPos > 0 ? '+'
  95 + +
  96 + item.thicknessTolPos : item.thicknessTolPos }}
  97 + </view>
  98 + <view v-if="item.thicknessTolNeg" class="value-spec_box_2">{{ item.thicknessTolNeg > 0 ? '+'
  99 + +
  100 + item.thicknessTolNeg : item.thicknessTolNeg }}
  101 + </view>
  102 + </view>
  103 + <view v-if="item.width" class="value-spec_val p12">*</view>
  104 + <view v-if="item.width" class="value-spec_val">{{ item.width }}</view>
  105 + <view v-if="item.width" class="value-spec_box">
  106 + <view v-if="item.widthTolPos" class="value-spec_box_1">{{ item.widthTolPos > 0 ? '+' +
  107 + item.widthTolPos : item.widthTolPos }}
  108 + </view>
  109 + <view v-if="item.widthTolNeg" class="value-spec_box_2">{{ item.widthTolNeg > 0 ? '+' +
  110 + item.widthTolNeg : item.widthTolNeg }}
  111 + </view>
  112 + </view>
  113 + <view v-if="item.length" class="value-spec_val p12">*</view>
  114 + <view v-if="item.length" class="value-spec_val">{{ item.length }}</view>
  115 + <view v-if="item.length" class="value-spec_box">
  116 + <view v-if="item.lengthTolPos" class="value-spec_box_1">{{ item.lengthTolPos > 0 ? '+' +
  117 + item.lengthTolPos : item.lengthTolPos }}
  118 + </view>
  119 + <view v-if="item.lengthTolNeg" class="value-spec_box_2">{{ item.lengthTolNeg > 0 ? '+' +
  120 + item.lengthTolNeg : item.lengthTolNeg }}
  121 + </view>
  122 + </view>
  123 + </view>
  124 + </view>
  125 + <view class="row"><text class="label">状态</text><text class="value">{{ item.status }}</text></view>
  126 + <view class="row"><text class="label">发货日期</text><text class="value">{{ item.shipmentDate }}</text></view>
  127 + <view class="row"><text class="label">数量(kg)</text><text class="value">{{ item.quantity }}</text></view>
  128 + <view class="row"><text class="label">产量批次号</text><text class="value">{{ item.yieldBatchNo }}</text></view>
  129 + </view>
  130 + </view>
  131 +
  132 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" />
  133 + </view>
  134 +</template>
  135 +<script>
  136 +import { uuid } from '@/utils/uuid.js'
  137 +import SingleSelectSheet from '@/components/single-select/index.vue'
  138 +export default {
  139 + name: 'Product',
  140 + props: {
  141 + title: { type: String, default: '' },
  142 + mode: { type: String, default: 'add' },
  143 + list: { type: Array, default: () => [] },
  144 + max: { type: Number, default: 8 },
  145 + provideSamplesOptions: { type: Array, default: () => [] },
  146 + clearParametersOptions: { type: Array, default: () => [] },
  147 + },
  148 + components: { SingleSelectSheet },
  149 + data() {
  150 + return {
  151 + items: [],
  152 + collapsedView: false,
  153 + roleCodes: [],
  154 + sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1, mode: '' }
  155 + }
  156 + },
  157 + computed: {
  158 + minDeliveryDate() {
  159 + const s = this.orderDate
  160 + if (!s) return ''
  161 + const parts = String(s).split('-')
  162 + const y = Number(parts[0])
  163 + const m = Number(parts[1])
  164 + const d = Number(parts[2])
  165 + if (!y || !m || !d) return ''
  166 + const dt = new Date(y, m - 1, d)
  167 + dt.setDate(dt.getDate() + 1)
  168 + const yy = dt.getFullYear()
  169 + const mm = String(dt.getMonth() + 1).padStart(2, '0')
  170 + const dd = String(dt.getDate()).padStart(2, '0')
  171 + return `${yy}/${mm}/${dd}`
  172 + },
  173 + // roleCodes() {
  174 + // const g = this.$store && this.$store.getters
  175 + // return (g && g.roleCodes) || [];
  176 + // },
  177 + },
  178 + watch: {
  179 + items: {
  180 + handler() { this.emitChange() },
  181 + deep: true
  182 + },
  183 + list: {
  184 + handler(v) {
  185 + const arr = Array.isArray(v) ? v : []
  186 + this.items = arr.map(x => {
  187 + const it = { ...this.defaultItem(), ...x, collapsed: true }
  188 + return it
  189 + })
  190 + },
  191 + deep: true
  192 + },
  193 + },
  194 + created() {
  195 + const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, collapsed: false })) : [{ ...this.defaultItem(), collapsed: false }]
  196 + this.items = init;
  197 + },
  198 + methods: {
  199 + defaultItem() {
  200 + return {
  201 + purchaseOrderId: uuid(),
  202 + collapsed: false,
  203 + id: '',
  204 + // 厚度公差
  205 + thicknessTolPos: '',
  206 + thicknessTolNeg: '',
  207 + // 宽度公差
  208 + widthTolPos: '',
  209 + widthTolNeg: '',
  210 + // 长度公差
  211 + lengthTolPos: '',
  212 + lengthTolNeg: '',
  213 + // 其他字段
  214 + industry: '',
  215 + quality: '',
  216 + brand: '',
  217 + thickness: '',
  218 + width: '',
  219 + length: '',
  220 + status: '',
  221 + quantity: '',
  222 + shippedQuantity: '',
  223 + supplementaryQuantity: '',
  224 + confirmedDeliveryDate: '',
  225 + remarks: '',
  226 + }
  227 + },
  228 +
  229 + onAdd() {
  230 + const obj = this.defaultItem()
  231 + obj.collapsed = true
  232 + this.items.push(obj)
  233 + this.emitChange()
  234 + },
  235 + onRemove(id) {
  236 + if (!id) return
  237 + uni.showModal({
  238 + title: '系统提示',
  239 + content: '是否确定删除选中的产品?',
  240 + confirmText: '确定',
  241 + cancelText: '取消',
  242 + success: (res) => {
  243 + if (res && res.confirm) {
  244 + const i = this.items.findIndex(it => String(it.purchaseOrderId) === String(id))
  245 + if (i >= 0) {
  246 + this.items.splice(i, 1)
  247 + this.emitChange()
  248 + }
  249 + }
  250 + }
  251 + })
  252 + },
  253 + toggleItem(idx) {
  254 + const it = this.items[idx]
  255 + if (!it) return
  256 + it.collapsed = !it.collapsed
  257 + this.$set(this.items, idx, it)
  258 + },
  259 + emitChange() {
  260 + const out = this.items.map(it => ({ ...it }))
  261 + this.$emit('input', out)
  262 + this.$emit('update:value', out)
  263 + this.$emit('change', out)
  264 + },
  265 + onNonNegativeNumberInput(val, item, idx, field) {
  266 + let v = String(val != null ? val : (item && item[field]) || '')
  267 + v = v.replace(/[^0-9.]/g, '')
  268 + v = v.replace(/(\..*)\./g, '$1')
  269 + if (v.startsWith('.')) v = '0' + v
  270 + if (v === '') { item[field] = ''; if (typeof idx === 'number') this.$set(this.items, idx, { ...item }); return }
  271 + const num = Number(v)
  272 + if (isNaN(num) || num < 0) {
  273 + item[field] = '0'
  274 + } else {
  275 + item[field] = v
  276 + }
  277 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  278 + },
  279 + onNonNegativeNumberBlur(item, idx, field) {
  280 + const v = String((item && item[field]) || '')
  281 + const num = Number(v)
  282 + if (isNaN(num) || num < 0) item[field] = '0'
  283 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  284 + },
  285 + onRealNumberInput(val, item, idx, field) {
  286 + let s = String(val != null ? val : (item && item[field]) || '')
  287 + const neg = s.trim().startsWith('-')
  288 + s = s.replace(/[^0-9.\-]/g, '')
  289 + s = s.replace(/(?!^)-/g, '')
  290 + s = s.replace(/(\..*)\./g, '$1')
  291 + if (s.startsWith('.')) s = '0' + s
  292 + if (s.startsWith('-.')) s = '-0.' + s.slice(2)
  293 + if (neg && !s.startsWith('-')) s = '-' + s.replace(/-/g, '')
  294 + item[field] = s
  295 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  296 + },
  297 + onRealNumberBlur(item, idx, field) {
  298 + const s = String((item && item[field]) || '')
  299 + if (s === '') { if (typeof idx === 'number') this.$set(this.items, idx, { ...item }); return }
  300 + const n = Number(s)
  301 + if (isNaN(n)) item[field] = ''
  302 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  303 + },
  304 + // 限制输入为2位小数
  305 + onTwoDecimalInput(val, item, idx, field) {
  306 + let v = String(val != null ? val : (item && item[field]) || '')
  307 + v = v.replace(/[^0-9.]/g, '')
  308 + v = v.replace(/(\..*)\./g, '$1')
  309 +
  310 + // Restrict to 2 decimal places
  311 + const decimalIndex = v.indexOf('.')
  312 + if (decimalIndex !== -1 && v.length > decimalIndex + 3) {
  313 + v = v.substring(0, decimalIndex + 3)
  314 + }
  315 +
  316 + if (v.startsWith('.')) v = '0' + v
  317 +
  318 + // If the value was modified (truncated or cleaned)
  319 + if (String(val) !== v) {
  320 + // Hack: Temporarily set the dirty value to trigger Vue update mechanism
  321 + // This ensures that when we set the clean value back, Vue detects a change
  322 + item[field] = val
  323 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  324 +
  325 + // Then revert to the clean value asynchronously
  326 + setTimeout(() => {
  327 + item[field] = v
  328 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  329 + }, 0)
  330 + } else {
  331 + item[field] = v
  332 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  333 + }
  334 + },
  335 + onTwoDecimalBlur(item, idx, field) {
  336 + let v = String((item && item[field]) || '')
  337 + const num = Number(v)
  338 + if (isNaN(num) || num < 0) {
  339 + item[field] = '0'
  340 + } else {
  341 + if (v.endsWith('.')) {
  342 + item[field] = v.slice(0, -1)
  343 + }
  344 + }
  345 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  346 + },
  347 + toggleViewCollapse() {
  348 + this.collapsedView = !this.collapsedView
  349 + },
  350 + onDeliveryChange(e, item, idx) {
  351 + const getStr = (x) => {
  352 + if (x && x.detail && x.detail.value !== undefined) return x.detail.value
  353 + if (typeof x === 'string') return x
  354 + return item && item.deliveryDate ? item.deliveryDate : ''
  355 + }
  356 + const val = getStr(e)
  357 + if (!val || !this.orderDate) return
  358 + const parse = (s) => {
  359 + const p = String(s).replace(/\//g, '-').split('-')
  360 + const y = Number(p[0])
  361 + const m = Number(p[1])
  362 + const d = Number(p[2])
  363 + return new Date(y, m - 1, d)
  364 + }
  365 + const sel = parse(val)
  366 + const ord = parse(this.orderDate)
  367 + if (!(sel > ord)) {
  368 + item.deliveryDate = ''
  369 + this.$set(this.items, idx, { ...item })
  370 + uni.showToast({ title: '发货日期必须大于订货日期', icon: 'none' })
  371 + }
  372 + },
  373 + openProductSheet(idx, mode = 'provideSamples') {
  374 + let opts = []
  375 + let title = ''
  376 + let value = ''
  377 + const item = this.items[idx]
  378 +
  379 + if (mode === 'provideSamples') {
  380 + opts = this.provideSamplesOptions
  381 + value = item.provideSamples
  382 + title = '选择是否提供样品'
  383 + } else if (mode === 'clearParameters') {
  384 + opts = this.clearParametersOptions;
  385 + value = item.clearParameters
  386 + title = '是否提供明确参数'
  387 + }
  388 + console.log('____', { ...this.sheet, visible: true, title, options: opts, idx, value, mode })
  389 + this.sheet = { ...this.sheet, visible: true, title, options: opts, idx, value, mode }
  390 + },
  391 + onProductConfirm({ value, label }) {
  392 + const idx = this.sheet.idx
  393 + const _mode = this.sheet.mode;
  394 + const it = this.items[idx]
  395 + if (!it) { this.sheet.visible = false; return }
  396 + it[_mode] = value
  397 + it[_mode + 'Name'] = label || ''
  398 + this.$set(this.items, idx, it)
  399 + this.sheet.visible = false
  400 + this.emitChange()
  401 + },
  402 + }
  403 +}
  404 +</script>
  405 +<style lang="scss" scoped>
  406 +.header {
  407 + background-color: #fff;
  408 + display: flex;
  409 + align-items: center;
  410 + padding: 24rpx 32rpx;
  411 +
  412 + &.bp {
  413 + border-bottom: 1px solid #f0f0f0;
  414 + }
  415 +}
  416 +
  417 +.dot {
  418 + width: 16rpx;
  419 + height: 16rpx;
  420 + background: #3D48A3;
  421 + border-radius: 50%;
  422 + margin-right: 12rpx;
  423 +}
  424 +
  425 +.title {
  426 + font-size: 32rpx;
  427 + color: rgba(0, 0, 0, 0.9);
  428 + font-weight: 600;
  429 +}
  430 +
  431 +.ops {
  432 + margin-left: auto;
  433 +}
  434 +
  435 +.op {
  436 + color: $theme-primary;
  437 + font-size: 28rpx;
  438 + margin-left: 8rpx;
  439 +}
  440 +
  441 +.op1 {
  442 + display: flex;
  443 + align-items: center;
  444 +}
  445 +
  446 +.opAdd {
  447 + color: rgba(0, 0, 0, 0.6);
  448 + width: 40rpx;
  449 + height: 40rpx;
  450 +}
  451 +
  452 +.opCollapse {
  453 + color: rgba(0, 0, 0, 0.6);
  454 + width: 32rpx;
  455 + height: 28rpx;
  456 + margin-right: 16rpx;
  457 +}
  458 +
  459 +::v-deep .uni-list {
  460 + background: transparent;
  461 +
  462 + .uni-list--border-top {
  463 + background-color: transparent !important;
  464 + }
  465 +
  466 + &-item {
  467 + &__extra-text {
  468 + font-size: 32rpx;
  469 + }
  470 +
  471 + &__content-title {
  472 + font-size: 32rpx;
  473 + color: rgba(0, 0, 0, 0.9);
  474 + }
  475 +
  476 + &__container {
  477 + padding: 32rpx;
  478 +
  479 + .uni-easyinput {
  480 +
  481 + .is-disabled {
  482 + background-color: transparent !important;
  483 + }
  484 +
  485 + &__placeholder-class {
  486 + font-size: 32rpx;
  487 + color: rgba(0, 0, 0, 0.4);
  488 + }
  489 +
  490 + &__content {
  491 + border: none;
  492 +
  493 + &-input {
  494 + padding-left: 0 !important;
  495 + height: 48rpx;
  496 + line-height: 48rpx;
  497 + font-size: 32rpx;
  498 + }
  499 +
  500 + .content-clear-icon {
  501 + font-size: 44rpx !important;
  502 + }
  503 + }
  504 + }
  505 +
  506 + .amount-row {
  507 + flex: 1;
  508 + display: flex;
  509 + align-items: center;
  510 +
  511 + .uni-easyinput {
  512 + flex: 1;
  513 + }
  514 +
  515 + .unit {
  516 + margin-left: 16rpx;
  517 + color: rgba(0, 0, 0, 0.9);
  518 + }
  519 + }
  520 +
  521 + .item-title,
  522 + .uni-list-item__content {
  523 + flex: none;
  524 + min-height: 48rpx;
  525 + line-height: 48rpx;
  526 + font-size: 32rpx;
  527 + position: relative;
  528 + width: 210rpx;
  529 + margin-right: 32rpx;
  530 + color: rgba(0, 0, 0, 0.9);
  531 + padding-right: 0;
  532 +
  533 +
  534 + .required {
  535 + color: red;
  536 + position: absolute;
  537 + top: 50%;
  538 + transform: translateY(-50%);
  539 + left: -16rpx;
  540 + }
  541 + }
  542 +
  543 + }
  544 +
  545 + &.select-item {
  546 + &.is-empty {
  547 + .uni-list-item__extra-text {
  548 + color: rgba(0, 0, 0, 0.4) !important;
  549 + }
  550 + }
  551 +
  552 + &.is-filled {
  553 + .uni-list-item__extra-text {
  554 + color: rgba(0, 0, 0, 0.9) !important;
  555 + }
  556 + }
  557 +
  558 + .serial-number-row {
  559 + display: flex;
  560 + align-items: center;
  561 + }
  562 +
  563 + }
  564 +
  565 + &.mgb10 {
  566 + margin-bottom: 20rpx;
  567 + }
  568 +
  569 + }
  570 +
  571 + .title-header {
  572 + background-color: #fff;
  573 + display: flex;
  574 + align-items: center;
  575 + padding: 32rpx 32rpx 22rpx;
  576 +
  577 + &_icon {
  578 + width: 32rpx;
  579 + height: 28rpx;
  580 + margin-right: 16rpx;
  581 + }
  582 +
  583 + span {
  584 + color: rgba(0, 0, 0, 0.9);
  585 + font-size: 32rpx;
  586 + line-height: 44rpx;
  587 + font-weight: 600;
  588 + }
  589 + }
  590 +}
  591 +
  592 +/* 只读 easyinput 根据内容自适应高度 */
  593 +::v-deep .uni-list-item__container {
  594 + align-items: flex-start;
  595 +}
  596 +
  597 +.block-ops {
  598 + display: flex;
  599 + padding: 20rpx 32rpx 20rpx;
  600 + justify-content: space-around;
  601 +}
  602 +
  603 +.del {
  604 + color: #D54941;
  605 + font-size: 28rpx;
  606 + display: flex;
  607 + align-items: center;
  608 +
  609 + image {
  610 + width: 40rpx;
  611 + height: 40rpx;
  612 + }
  613 +}
  614 +
  615 +.toggle {
  616 + color: $theme-primary;
  617 + font-size: 28rpx;
  618 + display: flex;
  619 + align-items: center;
  620 +
  621 + image {
  622 + width: 40rpx;
  623 + height: 40rpx;
  624 + }
  625 +}
  626 +
  627 +.section {
  628 + background: #f1f1f1;
  629 + margin-bottom: 20rpx;
  630 +
  631 + .block {
  632 + background: #ffffff;
  633 + // padding: 32rpx 0;
  634 + margin-bottom: 20rpx;
  635 +
  636 + &:last-child {
  637 + margin-bottom: 0;
  638 + }
  639 + }
  640 +
  641 + .row {
  642 + display: flex;
  643 + // margin-bottom: 24rpx;
  644 + line-height: 32rpx;
  645 + padding: 32rpx;
  646 + border-bottom: 1rpx solid #f2f2f2 !important;
  647 +
  648 +
  649 + &.noneStyle {
  650 + border-bottom: 0;
  651 + border-bottom: none;
  652 + }
  653 +
  654 + &.row-spec {
  655 + align-items: center;
  656 + }
  657 + }
  658 +
  659 + .row:last-child {
  660 + margin-bottom: 0;
  661 + }
  662 +
  663 + .label {
  664 + width: 210rpx;
  665 + margin-right: 32rpx;
  666 + color: rgba(0, 0, 0, 0.9);
  667 + font-size: 32rpx;
  668 + line-height: 48rpx;
  669 + }
  670 +
  671 + .value {
  672 + flex: 1;
  673 + color: rgba(0, 0, 0, 0.9);
  674 + font-size: 32rpx;
  675 + white-space: pre-wrap;
  676 + word-break: break-all;
  677 + line-height: 48rpx;
  678 + }
  679 +
  680 + .value-spec {
  681 + height: 48rpx;
  682 + display: flex;
  683 + align-items: center;
  684 + color: #000000;
  685 +
  686 + &_box {
  687 + position: relative;
  688 + width: 60rpx;
  689 + height: 48rpx;
  690 +
  691 + &_1 {
  692 + font-size: 16rpx;
  693 + position: absolute;
  694 + top: -10rpx;
  695 + left: 0;
  696 + }
  697 +
  698 + &_2 {
  699 + font-size: 16rpx;
  700 + position: absolute;
  701 + bottom: -10rpx;
  702 + left: 0;
  703 + }
  704 + }
  705 +
  706 + &_val {
  707 + font-size: 28rpx;
  708 +
  709 + &.p12 {
  710 + padding-right: 12rpx;
  711 + }
  712 + }
  713 + }
  714 +
  715 + .view-total {
  716 + padding-top: 20rpx;
  717 +
  718 + .head {
  719 + font-size: 32rpx;
  720 + font-weight: 600;
  721 + line-height: 50rpx;
  722 + color: rgba(0, 0, 0, 0.9);
  723 + padding-bottom: 16rpx;
  724 + margin-bottom: 24rpx;
  725 + border-bottom: 1px dashed #E7E7E7;
  726 + }
  727 +
  728 + .row {
  729 + display: flex;
  730 + margin-bottom: 24rpx;
  731 + line-height: 32rpx;
  732 +
  733 + .label {
  734 + width: 180rpx;
  735 + margin-right: 14rpx;
  736 + color: rgba(0, 0, 0, 0.6);
  737 + font-size: 28rpx;
  738 + }
  739 +
  740 + .value {
  741 + flex: 1;
  742 + color: rgba(0, 0, 0, 0.9);
  743 + font-size: 28rpx;
  744 + white-space: pre-wrap;
  745 + word-break: break-all;
  746 + }
  747 + }
  748 + }
  749 +}
  750 +
  751 +
  752 +.view-list {
  753 + padding: 26rpx 32rpx;
  754 + background: #ffffff;
  755 +
  756 + .card {
  757 + background: #f3f3f3;
  758 + border-radius: 16rpx;
  759 + padding: 32rpx 44rpx;
  760 + margin-bottom: 20rpx;
  761 +
  762 + &:last-child {
  763 + margin-bottom: 0;
  764 + }
  765 + }
  766 +
  767 + .row {
  768 + display: flex;
  769 + margin-bottom: 24rpx;
  770 + line-height: 32rpx;
  771 +
  772 + &.row-spec {
  773 + height: 60rpx;
  774 + align-items: center;
  775 + }
  776 + }
  777 +
  778 + .row:last-child {
  779 + margin-bottom: 0;
  780 + }
  781 +
  782 + .label {
  783 + width: 200rpx;
  784 + margin-right: 14rpx;
  785 + color: rgba(0, 0, 0, 0.6);
  786 + font-size: 28rpx;
  787 + }
  788 +
  789 + .value {
  790 + flex: 1;
  791 + color: rgba(0, 0, 0, 0.9);
  792 + font-size: 28rpx;
  793 + white-space: pre-wrap;
  794 + word-break: break-all;
  795 + }
  796 +
  797 + .value-spec {
  798 + height: 60rpx;
  799 + display: flex;
  800 + align-items: center;
  801 + color: #000000;
  802 +
  803 + &_box {
  804 + position: relative;
  805 + width: 60rpx;
  806 + height: 60rpx;
  807 +
  808 + &_1 {
  809 + font-size: 16rpx;
  810 + position: absolute;
  811 + top: 0;
  812 + left: 0;
  813 + }
  814 +
  815 + &_2 {
  816 + font-size: 16rpx;
  817 + position: absolute;
  818 + bottom: 0;
  819 + left: 0;
  820 + }
  821 + }
  822 +
  823 + &_val {
  824 + font-size: 28rpx;
  825 +
  826 + &.p12 {
  827 + padding-right: 12rpx;
  828 + }
  829 + }
  830 + }
  831 +
  832 + .view-total {
  833 + padding-top: 20rpx;
  834 +
  835 + .head {
  836 + font-size: 32rpx;
  837 + font-weight: 600;
  838 + line-height: 50rpx;
  839 + color: rgba(0, 0, 0, 0.9);
  840 + padding-bottom: 16rpx;
  841 + margin-bottom: 24rpx;
  842 + border-bottom: 1px dashed #E7E7E7;
  843 + }
  844 +
  845 + .row {
  846 + display: flex;
  847 + margin-bottom: 24rpx;
  848 + line-height: 32rpx;
  849 +
  850 + .label {
  851 + width: 180rpx;
  852 + margin-right: 14rpx;
  853 + color: rgba(0, 0, 0, 0.6);
  854 + font-size: 28rpx;
  855 + }
  856 +
  857 + .value {
  858 + flex: 1;
  859 + color: rgba(0, 0, 0, 0.9);
  860 + font-size: 28rpx;
  861 + white-space: pre-wrap;
  862 + word-break: break-all;
  863 + }
  864 + }
  865 + }
  866 +}
  867 +</style>
@@ -16,21 +16,20 @@ @@ -16,21 +16,20 @@
16 </view> 16 </view>
17 <view class="footer"> 17 <view class="footer">
18 <button v-if="extraBtnText" class="btn extra" @click="onExtra">{{ extraBtnText }}</button> 18 <button v-if="extraBtnText" class="btn extra" @click="onExtra">{{ extraBtnText }}</button>
19 - <button class="btn reject" @click="onReject">驳回</button>  
20 - <button class="btn pass" type="primary" @click="onPass">通过</button> 19 + <button class="btn reject" @click="onReject">{{ rejectText }}</button>
  20 + <button class="btn pass" type="primary" @click="onPass">{{ passText }}</button>
21 </view> 21 </view>
22 22
23 <uni-popup ref="approvePopup" type="center" :mask-click="false"> 23 <uni-popup ref="approvePopup" type="center" :mask-click="false">
24 <view class="action-modal"> 24 <view class="action-modal">
25 - <view class="action-modal_header">{{ approveType === 'PASS' ? '通过' : '驳回' }}</view> 25 + <view class="action-modal_header">{{ approveType === 'PASS' ? passText : rejectText }}</view>
26 <view class="action-modal_body"> 26 <view class="action-modal_body">
27 - <text class="tip">{{ approveType === 'PASS' ? '您将通过该信息的审核' : '您将驳回该信息的审核' }}</text>  
28 - <uni-easyinput v-model="message" :placeholder="approveType === 'PASS' ? '请输入通过原因' : '请输入驳回原因'" /> 27 + <text class="tip">{{ approveType === 'PASS' ? '您将' + passText + '该信息的审核' : '您将' + rejectText + '该信息的审核' }}</text>
  28 + <uni-easyinput v-model="message" :placeholder="approveType === 'PASS' ? '请输入' + passText + '原因' : '请输入' + rejectText + '原因'" />
29 </view> 29 </view>
30 <view class="action-modal_footer"> 30 <view class="action-modal_footer">
31 <button class="btn cancel" @click="cancelApprove">取消</button> 31 <button class="btn cancel" @click="cancelApprove">取消</button>
32 - <button class="btn confirm" type="primary" @click="confirmApprove">{{ approveType === 'PASS' ? '通过'  
33 - : '驳回' }}</button> 32 + <button class="btn confirm" type="primary" @click="confirmApprove">{{ approveType === 'PASS' ? passText : rejectText }}</button>
34 </view> 33 </view>
35 </view> 34 </view>
36 </uni-popup> 35 </uni-popup>
@@ -143,7 +142,9 @@ export default { @@ -143,7 +142,9 @@ export default {
143 customerInfo: { businessFileName: '', businessFileId: '', shareholderFileName: '', shareholderFileId: '' }, 142 customerInfo: { businessFileName: '', businessFileId: '', shareholderFileName: '', shareholderFileId: '' },
144 companyReview: { companySettlementPeriod: '', companyMaterialSupplyPlan: '', companySuggestedCategory: '', companySuggestedCategoryName: '', companyCreditLimit: '' }, 143 companyReview: { companySettlementPeriod: '', companyMaterialSupplyPlan: '', companySuggestedCategory: '', companySuggestedCategoryName: '', companyCreditLimit: '' },
145 categoryOptions: [], 144 categoryOptions: [],
146 - sheet: { visible: false, title: '请选择', options: [], value: '', field: '' } 145 + sheet: { visible: false, title: '请选择', options: [], value: '', field: '' },
  146 + passText: '通过',
  147 + rejectText: '驳回',
147 } 148 }
148 }, 149 },
149 computed: { 150 computed: {
@@ -176,6 +177,25 @@ export default { @@ -176,6 +177,25 @@ export default {
176 return text 177 return text
177 } 178 }
178 }, 179 },
  180 + watch: {
  181 + 'auditCtx.bizFlag': {
  182 + deep: true,
  183 + handler(v) {
  184 + console.log('审核__bizFlag', v)
  185 + if (v) {
  186 + // 产品试样确认单-审核 按钮文案
  187 + if (v === 'CONFIRMATION_SLIP_EDIT') {
  188 + this.passText = '同意生产'
  189 + this.rejectText = '不同意生产'
  190 + } else {
  191 + this.passText = '通过'
  192 + this.rejectText = '驳回'
  193 + }
  194 + }
  195 + },
  196 + immediate: true
  197 + }
  198 + },
179 onLoad() { 199 onLoad() {
180 const CACHE_KEY_2 = 'sourceBusinessId'; // 业务列表 跳转过来的数据存储key 200 const CACHE_KEY_2 = 'sourceBusinessId'; // 业务列表 跳转过来的数据存储key
181 const _sourceBusinessId = uni.getStorageSync(CACHE_KEY_2) || ''; 201 const _sourceBusinessId = uni.getStorageSync(CACHE_KEY_2) || '';
@@ -270,6 +290,7 @@ export default { @@ -270,6 +290,7 @@ export default {
270 }, 290 },
271 // 驳回 291 // 驳回
272 onReject() { 292 onReject() {
  293 + console.log('FormValues__', this.$refs.basicRef.getFormValues());
273 this.approveType = 'REFUSE' 294 this.approveType = 'REFUSE'
274 this.message = '' 295 this.message = ''
275 this.$refs.approvePopup.open() 296 this.$refs.approvePopup.open()
@@ -277,6 +298,7 @@ export default { @@ -277,6 +298,7 @@ export default {
277 // 通过 298 // 通过
278 // 在这里增加业务判断 比如 资信管理,判断有没有填写客户信息、公司评审(这些是不同角色进行操作的) 299 // 在这里增加业务判断 比如 资信管理,判断有没有填写客户信息、公司评审(这些是不同角色进行操作的)
279 onPass() { 300 onPass() {
  301 + console.log('FormValues__', this.$refs.basicRef.getFormValues());
280 // 校验表单 302 // 校验表单
281 if (!this.basicRefCheck()) { 303 if (!this.basicRefCheck()) {
282 return 304 return
@@ -410,7 +432,7 @@ export default { @@ -410,7 +432,7 @@ export default {
410 console.log('审核__approvePass', res) 432 console.log('审核__approvePass', res)
411 if (res.code === 200) { 433 if (res.code === 200) {
412 uni.showToast({ 434 uni.showToast({
413 - title: '已通过', 435 + title: '已' + this.passText,
414 icon: 'none' 436 icon: 'none'
415 }) 437 })
416 setTimeout(() => { 438 setTimeout(() => {
@@ -423,7 +445,7 @@ export default { @@ -423,7 +445,7 @@ export default {
423 console.log('审核__approveRefuse', res) 445 console.log('审核__approveRefuse', res)
424 if (res.code === 200) { 446 if (res.code === 200) {
425 uni.showToast({ 447 uni.showToast({
426 - title: '已驳回', 448 + title: '已' + this.rejectText,
427 icon: 'none' 449 icon: 'none'
428 }) 450 })
429 setTimeout(() => { 451 setTimeout(() => {
@@ -435,7 +457,7 @@ export default { @@ -435,7 +457,7 @@ export default {
435 console.log('审核__confirmApprove', payload) 457 console.log('审核__confirmApprove', payload)
436 this.$refs.approvePopup.close() 458 this.$refs.approvePopup.close()
437 uni.showToast({ 459 uni.showToast({
438 - title: this.approveType === 'PASS' ? '已通过' : '已驳回', 460 + title: this.approveType === 'PASS' ? '已' + this.passText : '已' + this.rejectText,
439 icon: 'none' 461 icon: 'none'
440 }) 462 })
441 } 463 }
  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.customerName }}</text>
  7 + <view :class="['status', `status_${form.status}`]" />
  8 + <view class="row"><text class="label">订单编号</text><text class="value">{{ form.orderCode }}</text></view>
  9 + <view class="row"><text class="label">生产厂</text><text class="value">{{ form.workshopName }}</text></view>
  10 + </view>
  11 +
  12 + <!-- 产品 -->
  13 + <view class="section2">
  14 + <Product mode="view" :list="form.detailList" />
  15 + </view>
  16 +
  17 + <view class="title-header">
  18 + <image class="title-header_icon" src="/static/images/title.png" />
  19 + <span>本次试样概况</span>
  20 + </view>
  21 +
  22 + <view class="section">
  23 + <view class="row"><text class="label">表面</text><text class="value">{{ form.surface }}</text></view>
  24 + <view class="row"><text class="label">性能</text><text class="value">{{ form.performance }}</text></view>
  25 + <view class="row"><text class="label">公差</text><text class="value">{{ form.tolerance }}</text></view>
  26 + <view class="row"><text class="label">带型</text><text class="value">{{ form.bandingPattern }}</text></view>
  27 + <view class="row"><text class="label">包装</text><text class="value">{{ form.packaging }}</text></view>
  28 + <view class="row"><text class="label">件重条头</text><text class="value">{{ form.weight }}</text></view>
  29 + <view class="row"><text class="label">其他</text><text class="value">{{ form.other }}</text></view>
  30 + <view class="row"><text class="label">结论</text><text class="value">{{ getDicName('SAMPLE_RESULT',
  31 + form.sampleResult, dicOptions.SAMPLE_RESULT) }}</text></view>
  32 + <view class="row"><text class="label"></text><text class="value">{{ getDicName('SAMPLE_RESULT_SUB',
  33 + form.sampleResultSub, dicOptions.SAMPLE_RESULT_SUB) }}</text></view>
  34 + </view>
  35 + <view class="section">
  36 + <view class="row"><text class="label">客户评价依据</text><text class="value act"
  37 + @click="downloadFile(form.customerReviewsFileId, form.customerReviewsFileName)">{{
  38 + form.customerReviewsFileName
  39 + }}</text></view>
  40 + </view>
  41 + </view>
  42 + </scroll-view>
  43 + <detail-buttons :buttons="displayButtons" @click="handleButtonClick" />
  44 + </view>
  45 +</template>
  46 +
  47 +<script>
  48 +import { getDetailApi } from '@/api/follow_up_form.js'
  49 +import Product from './product.vue'
  50 +import DetailButtons from '@/components/detail-buttons/index.vue'
  51 +import { downloadFile } from '@/utils/downloadFile.js'
  52 +import {
  53 + getDicByCodes
  54 +} from '@/utils/dic'
  55 +import {
  56 + getDicName
  57 +} from '@/utils/dic.js'
  58 +
  59 +export default {
  60 + name: 'FollowUpFormDetail',
  61 + components: { Product, DetailButtons },
  62 + data() {
  63 + return {
  64 + form: {},
  65 + buttons: [
  66 + { text: '编辑', visible: true, variant: 'outline', event: 'edit' },
  67 + { text: '审核详情', visible: true, variant: 'outline', event: 'auditDetail' },
  68 + { text: '审核', visible: true, variant: 'primary', event: 'audit' },
  69 + ],
  70 + dicOptions: {
  71 + SAMPLE_RESULT: [],
  72 + SAMPLE_RESULT_SUB: []
  73 + },
  74 + sampleResultLocal: [],
  75 + sampleResultSubLocal: []
  76 + }
  77 + },
  78 + computed: {
  79 + statusFlags() {
  80 + const m = this.form || {}
  81 + const e = String(m.status || '')
  82 + return {
  83 + // 跟踪单编辑:1:审核状态为空、已驳回 2:showAudit为true 3:需要加角色权限
  84 + canEdit: (!e || e === 'REFUSE') && m.showAudit || false,
  85 + canAudit: e === 'AUDIT' && m.showExamine || false,
  86 + canAuditDetail: !!e || false,
  87 + }
  88 + },
  89 + displayButtons() {
  90 + const f = this.statusFlags;
  91 + console.log('displayButtons_f', f)
  92 + return [
  93 + { ...this.buttons[0], visible: f.canEdit && this.$auth.hasPermi('sample-order:follow-up-form:modify') },
  94 + { ...this.buttons[1], visible: f.canAuditDetail && this.$auth.hasPermi('sample-order:follow-up-form:review') },
  95 + { ...this.buttons[2], visible: f.canAudit && this.$auth.hasPermi('sample-order:follow-up-form:approve') },
  96 + ]
  97 + }
  98 + },
  99 + onLoad(query) {
  100 + const id = (query && (query.id || query.code)) || ''
  101 + if (id) {
  102 + this.loadDetail(id)
  103 + this.loadAllDicData()
  104 + }
  105 + },
  106 + methods: {
  107 + async loadDetail(id) {
  108 + try {
  109 + const res = await getDetailApi(id)
  110 + this.form = res.data || {}
  111 + } catch (e) {
  112 + this.form = {}
  113 + }
  114 + },
  115 + handleButtonClick(btn) {
  116 + if (!btn || btn.disabled) return
  117 + const map = {
  118 + edit: () => this.onEdit(),
  119 + auditDetail: () => this.onAuditDetail(),
  120 + audit: () => this.onAudit(),
  121 + }
  122 + const fn = map[btn.event]
  123 + if (typeof fn === 'function') fn()
  124 + },
  125 + onEdit() {
  126 + const id = this.form.id || this.form.code
  127 + if (id) uni.navigateTo({ url: `/pages/follow_up_form/modify?id=${id}` })
  128 + },
  129 + onAuditDetail() {
  130 + uni.setStorageSync('sourceBusinessId', this.form.id)
  131 + uni.navigateTo({ url: '/pages/flow/audit_detail' })
  132 + },
  133 + onAudit() {
  134 + uni.setStorageSync('sourceBusinessId', this.form.id)
  135 + uni.navigateTo({ url: '/pages/flow/audit' })
  136 + },
  137 + downloadFile,
  138 + getDicName,
  139 + loadAllDicData() {
  140 + const dicCodes = ['SAMPLE_RESULT', 'SAMPLE_RESULT_SUB']
  141 + return getDicByCodes(dicCodes).then(results => {
  142 + this.dicOptions.SAMPLE_RESULT = results.SAMPLE_RESULT.data || []
  143 + this.dicOptions.SAMPLE_RESULT_SUB = results.SAMPLE_RESULT_SUB.data || []
  144 + this.sampleResultLocal = (this.dicOptions.SAMPLE_RESULT || []).map(it => ({
  145 + value: it.code,
  146 + text: it.name
  147 + }))
  148 + this.sampleResultSubLocal = (this.dicOptions.SAMPLE_RESULT_SUB || []).map(it => ({
  149 + value: it.code,
  150 + text: it.name
  151 + }))
  152 + }).catch(() => {
  153 + this.dicOptions = {
  154 + SAMPLE_RESULT: [],
  155 + SAMPLE_RESULT_SUB: []
  156 + }
  157 + this.sampleResultLocal = []
  158 + this.sampleResultSubLocal = []
  159 + })
  160 + },
  161 + }
  162 +}
  163 +</script>
  164 +
  165 +<style lang="scss" scoped>
  166 +.page {
  167 + display: flex;
  168 + flex-direction: column;
  169 + height: 100vh;
  170 +}
  171 +
  172 +.scroll {
  173 + flex: 1;
  174 + background: #f3f3f3;
  175 +}
  176 +
  177 +.detail-page {
  178 + padding-bottom: 150rpx;
  179 +}
  180 +
  181 +.section {
  182 + padding: 32rpx;
  183 + background: #fff;
  184 + margin-bottom: 20rpx;
  185 + position: relative;
  186 +
  187 + .status {
  188 + position: absolute;
  189 + top: 16rpx;
  190 + right: 52rpx;
  191 + width: 180rpx;
  192 + height: 146rpx;
  193 + background-repeat: no-repeat;
  194 + background-size: 100% 100%;
  195 + background-position: center;
  196 +
  197 + &_AUDIT {
  198 + background-image: url('~@/static/images/dev_manage/status_1.png');
  199 + }
  200 +
  201 + &_PASS {
  202 + background-image: url('~@/static/images/dev_manage/status_2.png');
  203 + }
  204 +
  205 + &_REFUSE {
  206 + background-image: url('~@/static/images/dev_manage/status_3.png');
  207 + }
  208 +
  209 + &_CANCEL {
  210 + background-image: url('~@/static/images/dev_manage/status_4.png');
  211 + }
  212 +
  213 + }
  214 +}
  215 +
  216 +.row {
  217 + display: flex;
  218 + margin-bottom: 28rpx;
  219 +
  220 + &:last-child {
  221 + margin-bottom: 0;
  222 + }
  223 +
  224 + &.company {
  225 + font-size: 36rpx;
  226 + font-weight: 600;
  227 + color: rgba(0, 0, 0, 0.9);
  228 + padding-top: 10rpx;
  229 + margin-bottom: 32rpx;
  230 + line-height: 50rpx;
  231 + }
  232 +
  233 + .label {
  234 + max-width: 400rpx;
  235 + margin-right: 20rpx;
  236 + line-height: 32rpx;
  237 + font-size: 28rpx;
  238 + color: rgba(0, 0, 0, 0.6);
  239 + }
  240 +
  241 + .value {
  242 + flex: 1;
  243 + line-height: 32rpx;
  244 + font-size: 28rpx;
  245 + color: rgba(0, 0, 0, 0.9);
  246 + text-align: right;
  247 + word-break: break-all;
  248 +
  249 + &.act {
  250 + color: $theme-primary;
  251 + }
  252 +
  253 + }
  254 +}
  255 +
  256 +.title-header {
  257 + background-color: #fff;
  258 + display: flex;
  259 + align-items: center;
  260 + padding: 32rpx 32rpx 22rpx;
  261 + border-bottom: 1rpx dashed #f0f0f0;
  262 +
  263 + &_icon {
  264 + width: 32rpx;
  265 + height: 28rpx;
  266 + margin-right: 16rpx;
  267 + }
  268 +
  269 + span {
  270 + color: rgba(0, 0, 0, 0.9);
  271 + font-size: 32rpx;
  272 + line-height: 44rpx;
  273 + font-weight: 600;
  274 + }
  275 +}
  276 +
  277 +.section2 {
  278 + background: #f1f1f1;
  279 + margin-bottom: 20rpx;
  280 +}
  281 +
  282 +
  283 +.section3 {
  284 + padding: 0 32rpx;
  285 + background-color: #fff;
  286 + margin: 20rpx 0;
  287 +}
  288 +
  289 +.view-total {
  290 + padding-bottom: 20rpx;
  291 +
  292 + .head {
  293 + font-size: 32rpx;
  294 + font-weight: 600;
  295 + line-height: 50rpx;
  296 + color: rgba(0, 0, 0, 0.9);
  297 + padding-bottom: 16rpx;
  298 + margin-bottom: 24rpx;
  299 + border-bottom: 1px dashed #E7E7E7;
  300 + }
  301 +
  302 + .row {
  303 + display: flex;
  304 + margin-bottom: 24rpx;
  305 + line-height: 32rpx;
  306 +
  307 + .row2 {
  308 + width: 50%;
  309 + }
  310 +
  311 + .label {
  312 + width: 180rpx;
  313 + margin-right: 14rpx;
  314 + color: rgba(0, 0, 0, 0.6);
  315 + font-size: 28rpx;
  316 + }
  317 +
  318 + .value {
  319 + flex: 1;
  320 + color: rgba(0, 0, 0, 0.9);
  321 + font-size: 28rpx;
  322 + white-space: pre-wrap;
  323 + word-break: break-all;
  324 + }
  325 + }
  326 +}
  327 +</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.customerName }}</text>
  23 + <text :class="['status', `status_${item.status}`]">{{ filterStatus(item.status) }}</text>
  24 + </view>
  25 + <view class="info-row">
  26 + <text>订单编号</text><text>{{ item.orderCode || '-' }}</text>
  27 + </view>
  28 + <view class="info-row">
  29 + <text>生产厂</text><text>{{ item.workshopName || '-' }}</text>
  30 + </view>
  31 + </view>
  32 + </template>
  33 + </card-list>
  34 + </view>
  35 +
  36 +
  37 +
  38 + <!-- 筛选弹框 -->
  39 + <filter-modal :visible.sync="filterVisible" :value.sync="filterForm" title="筛选" @reset="onFilterReset"
  40 + @confirm="onFilterConfirm">
  41 + <template v-slot="{ model }">
  42 + <view class="filter-form">
  43 + <view class="form-item">
  44 + <view class="label">生产厂</view>
  45 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  46 + v-model="model.workshopId" @change="onWorkshopChange" :localdata="workshopOptions" />
  47 + </view>
  48 + <view class="form-item">
  49 + <view class="label">审核状态</view>
  50 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  51 + v-model="model.status" @change="onStatusChange" :localdata="statusLocal" />
  52 + </view>
  53 + <!-- <view class="form-item">
  54 + <view class="label">试样种类</view>
  55 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  56 + v-model="model.sampleType" @change="onSampleTypeChange" :localdata="sampleTypeLocal" />
  57 + </view>
  58 + <view class="form-item">
  59 + <view class="label">客户类型</view>
  60 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  61 + v-model="model.customerType" @change="onEnterpriseTypeChange" :localdata="enterpriseTypeLocal" />
  62 + </view> -->
  63 + </view>
  64 + </template>
  65 + </filter-modal>
  66 + </view>
  67 +</template>
  68 +
  69 +<script>
  70 +import CardList from '@/components/card/index.vue'
  71 +import FilterModal from '@/components/filter/index.vue'
  72 +import { workshopQueryApi } from '@/api/devManage.js'
  73 +import SingleSelectSheet from '@/components/single-select/index.vue'
  74 +import {
  75 + queryApi
  76 +} from '@/api/follow_up_form.js'
  77 +import {
  78 + getDicByCodes
  79 +} from '@/utils/dic'
  80 +
  81 +export default {
  82 + components: {
  83 + CardList,
  84 + FilterModal,
  85 + SingleSelectSheet
  86 + },
  87 + data() {
  88 + return {
  89 + searchKeyword: '',
  90 + searchKeywordDebounced: '',
  91 + tabs: [],
  92 + // 给到 card 的筛选值
  93 + query: {
  94 + status: '',
  95 + workshopId: '',
  96 + },
  97 + extraParams: {},
  98 +
  99 + // 批量选择
  100 + rowKey: 'id',
  101 + currentItems: [],
  102 +
  103 + // 筛选弹框
  104 + filterVisible: false,
  105 + filterForm: {
  106 + status: '',
  107 + workshopId: '',
  108 + },
  109 + dicOptions: {
  110 + AUDIT_STATUS: [], // 审核
  111 + },
  112 + statusLocal: [],
  113 + workshopOptions: [],
  114 + }
  115 + },
  116 + computed: {
  117 + extraCombined() {
  118 + return {
  119 + searchKey: this.searchKeywordDebounced || undefined
  120 + }
  121 + }
  122 + },
  123 + watch: {
  124 + extraCombined: {
  125 + deep: true,
  126 + handler(v) {
  127 + this.extraParams = v
  128 + },
  129 + immediate: true
  130 + },
  131 +
  132 + },
  133 + created() {
  134 + this.loadAllDicData()
  135 + this.loadWorkshopOptions()
  136 + },
  137 + onLoad() { },
  138 + // 页面触底兜底:当页面自身滚动到底部时,转调卡片组件加载更多
  139 + onReachBottom() {
  140 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) {
  141 + this.$refs.cardRef.onLoadMore()
  142 + }
  143 + },
  144 + beforeDestroy() {
  145 + if (this.searchDebounceTimer) {
  146 + clearTimeout(this.searchDebounceTimer)
  147 + this.searchDebounceTimer = null
  148 + }
  149 + },
  150 + methods: {
  151 + async loadWorkshopOptions() {
  152 + try {
  153 + const res = await workshopQueryApi({ pageIndex: 1, pageSize: 9999 })
  154 + const list = (res && res.data && res.data.datas) || []
  155 + this.workshopOptions = list.map(it => ({ text: it.name || it.workshopName || '', value: it.id || it.workshopId || '' }))
  156 + } catch (e) {
  157 + this.workshopOptions = []
  158 + }
  159 + },
  160 + onCardLoaded({
  161 + items
  162 + }) {
  163 + this.currentItems = items
  164 + },
  165 + onCardError() {
  166 + uni.showToast({
  167 + title: '列表加载失败',
  168 + icon: 'none'
  169 + })
  170 + },
  171 + // 输入实时搜索:1200ms 防抖,仅在停止输入超过阈值后刷新
  172 + onSearchInput(val) {
  173 + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer)
  174 + this.searchDebounceTimer = setTimeout(() => {
  175 + this.searchKeywordDebounced = this.searchKeyword
  176 + this.searchDebounceTimer = null
  177 + }, 1200)
  178 + },
  179 + // uni-search-bar 确认搜索:更新关键字并触发 CardList 刷新
  180 + search(e) {
  181 + const val = e && e.value != null ? e.value : this.searchKeyword
  182 + this.searchKeyword = val
  183 + this.searchKeywordDebounced = val
  184 + },
  185 + onAdd() {
  186 + uni.navigateTo({
  187 + url: '/pages/follow_up_form/add'
  188 + })
  189 + },
  190 + openFilter() {
  191 + this.filterVisible = true
  192 + },
  193 + onFilterReset(payload) {
  194 + this.filterForm = payload
  195 + },
  196 + onFilterConfirm(payload) {
  197 + if ((payload.status === '' || payload.status == null) && this.filterForm.status !== '') {
  198 + payload.status = this.filterForm.status
  199 + }
  200 + this.query = {
  201 + ...payload
  202 + }
  203 + },
  204 + onStatusChange(e) {
  205 + const raw = e && e.detail && e.detail.value !== undefined ?
  206 + e.detail.value :
  207 + (e && e.value !== undefined ? e.value : '')
  208 + this.filterForm.status = raw
  209 + },
  210 +
  211 + onSampleTypeChange(e) {
  212 + const raw = e && e.detail && e.detail.value !== undefined ?
  213 + e.detail.value :
  214 + (e && e.value !== undefined ? e.value : '')
  215 + this.filterForm.sampleType = raw
  216 + },
  217 +
  218 + onEnterpriseTypeChange(e) {
  219 + const raw = e && e.detail && e.detail.value !== undefined ?
  220 + e.detail.value :
  221 + (e && e.value !== undefined ? e.value : '')
  222 + this.filterForm.customerType = raw
  223 + },
  224 +
  225 + // 列表接口(真实请求)
  226 + fetchList({
  227 + pageIndex,
  228 + pageSize,
  229 + query,
  230 + extra
  231 + }) {
  232 + const params = {
  233 + pageIndex,
  234 + pageSize,
  235 + ...extra,
  236 + ...query
  237 + }
  238 + if (this.searchKeywordDebounced) {
  239 + params.searchKey = this.searchKeywordDebounced
  240 + }
  241 + return queryApi(params)
  242 + .then(res => {
  243 + const _data = res.data || {};
  244 + const records = _data.datas || [];
  245 + const totalCount = _data.totalCount || 0;
  246 + const hasNext = _data.hasNext || false
  247 + return {
  248 + records,
  249 + totalCount,
  250 + hasNext
  251 + }
  252 + })
  253 + .catch(err => {
  254 + console.error('fetchList error', err)
  255 + this.onCardError()
  256 + return {
  257 + records: [],
  258 + totalCount: 0,
  259 + hasNext: false
  260 + }
  261 + })
  262 + },
  263 + loadAllDicData() {
  264 + const dicCodes = ['AUDIT_STATUS']
  265 + return getDicByCodes(dicCodes).then(results => {
  266 + this.dicOptions.AUDIT_STATUS = results.AUDIT_STATUS.data || []
  267 + this.statusLocal = (this.dicOptions.AUDIT_STATUS || []).map(it => ({
  268 + value: it.code,
  269 + text: it.name
  270 + }))
  271 + }).catch(() => {
  272 + this.dicOptions = {
  273 + AUDIT_STATUS: [],
  274 + }
  275 + this.statusLocal = []
  276 + })
  277 + },
  278 + onCardClick(item) {
  279 + const id = (item && (item.id || item.code)) || ''
  280 + if (!id) return
  281 + const query = '?id=' + encodeURIComponent(id)
  282 + uni.navigateTo({
  283 + url: '/pages/follow_up_form/detail' + query
  284 + })
  285 + },
  286 + onWorkshopChange(e) {
  287 + const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ? e.value : '')
  288 + this.filterForm.workshopId = raw
  289 + const match = (this.workshopOptions || []).find(o => String(o.value) === String(raw))
  290 + this.filterForm.workshopIdName = match ? (match.text || '') : ''
  291 + },
  292 + filterStatus(status) {
  293 + const _item = this.statusLocal.filter(item => item.value === status)[0] || {};
  294 + return _item.text || '';
  295 + },
  296 + }
  297 +}
  298 +</script>
  299 +
  300 +<style lang="scss" scoped>
  301 +.page {
  302 + display: flex;
  303 + flex-direction: column;
  304 + height: 100vh;
  305 +}
  306 +
  307 +.dev-list-fixed {
  308 + position: fixed;
  309 + top: 96rpx;
  310 + left: 0;
  311 + right: 0;
  312 + z-index: 2;
  313 + background: #fff;
  314 +
  315 + .search-row {
  316 + display: flex;
  317 + align-items: center;
  318 + padding: 16rpx 32rpx;
  319 +
  320 + .uni-searchbar {
  321 + padding: 0;
  322 + flex: 1;
  323 + }
  324 +
  325 + .tool-icons {
  326 + display: flex;
  327 +
  328 + .tool-icon {
  329 + width: 48rpx;
  330 + height: 48rpx;
  331 + display: block;
  332 + margin-left: 32rpx;
  333 + }
  334 + }
  335 + }
  336 +
  337 +}
  338 +
  339 +/* 仅当前页覆盖 uni-search-bar 盒子高度 */
  340 +::v-deep .uni-searchbar__box {
  341 + height: 80rpx !important;
  342 + justify-content: start;
  343 +
  344 + .uni-searchbar__box-search-input {
  345 + font-size: 32rpx !important;
  346 + }
  347 +}
  348 +
  349 +.list-box {
  350 + flex: 1;
  351 + padding-top: 140rpx;
  352 +
  353 + &.pad-batch {
  354 + padding-bottom: 144rpx;
  355 + }
  356 +
  357 + .card {
  358 + position: relative;
  359 + }
  360 +
  361 + .card-header {
  362 + margin-bottom: 28rpx;
  363 + position: relative;
  364 +
  365 + .title {
  366 + font-size: 36rpx;
  367 + font-weight: 600;
  368 + line-height: 50rpx;
  369 + color: rgba(0, 0, 0, 0.9);
  370 + width: 578rpx;
  371 + }
  372 +
  373 + .status {
  374 + font-weight: 600;
  375 + position: absolute;
  376 + top: -32rpx;
  377 + right: -12rpx;
  378 + height: 48rpx;
  379 + line-height: 48rpx;
  380 + color: #fff;
  381 + font-size: 24rpx;
  382 + padding: 0 14rpx;
  383 + border-radius: 6rpx;
  384 +
  385 + // 审核中
  386 + &.status_AUDIT {
  387 + background: $theme-primary;
  388 + }
  389 +
  390 + // 审核通过
  391 + &.status_PASS {
  392 + background: #2BA471;
  393 + }
  394 +
  395 + // 已驳回
  396 + &.status_REFUSE {
  397 + background: #d54941;
  398 + }
  399 +
  400 + // 已取消
  401 + &.status_CANCEL {
  402 + background: #e7e7e7;
  403 + color: rgba(0, 0, 0, 0.6);
  404 + }
  405 +
  406 + }
  407 +
  408 + }
  409 +
  410 + .info-row {
  411 + display: flex;
  412 + align-items: center;
  413 + color: rgba(0, 0, 0, 0.6);
  414 + font-size: 28rpx;
  415 + margin-bottom: 24rpx;
  416 +
  417 + &:last-child {
  418 + margin-bottom: 0;
  419 + }
  420 +
  421 + text {
  422 + width: 60%;
  423 + line-height: 32rpx;
  424 +
  425 + &:last-child {
  426 + color: rgba(0, 0, 0, 0.9);
  427 + width: 40%;
  428 + }
  429 +
  430 + &.category {
  431 + display: inline-block;
  432 + padding: 4rpx 12rpx;
  433 + border-radius: 6rpx;
  434 + font-size: 24rpx;
  435 + width: auto;
  436 +
  437 + &.category_A {
  438 + background: #FFF0ED;
  439 + color: #D54941;
  440 + }
  441 +
  442 + &.category_B {
  443 + background: #FFF1E9;
  444 + color: #E37318;
  445 + }
  446 +
  447 + &.category_C {
  448 + background: #F2F3FF;
  449 + color: $theme-primary;
  450 + }
  451 +
  452 + &.category_D {
  453 + background: #E3F9E9;
  454 + color: #2BA471;
  455 + }
  456 + }
  457 + }
  458 +
  459 + }
  460 +}
  461 +
  462 +.filter-form {
  463 + .form-item {
  464 + margin-bottom: 24rpx;
  465 + }
  466 +
  467 + .label {
  468 + margin-bottom: 20rpx;
  469 + color: rgba(0, 0, 0, 0.9);
  470 + height: 44rpx;
  471 + line-height: 44rpx;
  472 + font-size: 30rpx;
  473 + }
  474 +
  475 + .uni-easyinput {
  476 + border: 1rpx solid #f3f3f3;
  477 + }
  478 +
  479 +}
  480 +
  481 +/* 深度覆盖 uni-data-checkbox(mode=tag)内部的 tag 展示与间距 */
  482 +::v-deep .filter-form .uni-data-checklist .checklist-group {
  483 + .checklist-box {
  484 + &.is--tag {
  485 + width: 212rpx;
  486 + margin-top: 0;
  487 + margin-bottom: 24rpx;
  488 + margin-right: 24rpx;
  489 + height: 80rpx;
  490 + padding: 0 20rpx;
  491 + border-radius: 12rpx;
  492 + background-color: #f3f3f3;
  493 + border-color: #f3f3f3;
  494 +
  495 + &:nth-child(3n) {
  496 + margin-right: 0;
  497 + }
  498 +
  499 + .checklist-content {
  500 + display: flex;
  501 + justify-content: center;
  502 + }
  503 +
  504 + .checklist-text {
  505 + color: rgba(0, 0, 0, 0.9);
  506 + font-size: 28rpx;
  507 + text-align: center;
  508 + }
  509 + }
  510 +
  511 + &.is-checked {
  512 + background-color: $theme-primary-plain-bg !important;
  513 + border-color: $theme-primary-plain-bg !important;
  514 +
  515 + .checklist-text {
  516 + color: $theme-primary !important;
  517 + }
  518 + }
  519 + }
  520 +
  521 +}
  522 +</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.customerName }}</view>
  9 + </template>
  10 + </uni-list-item>
  11 + <uni-list-item title="订单编号">
  12 + <template v-slot:footer>
  13 + <view class="readonly-text">{{ form.orderCode }}</view>
  14 + </template>
  15 + </uni-list-item>
  16 + <uni-list-item title="生产厂">
  17 + <template v-slot:footer>
  18 + <view class="readonly-text">{{ form.workshopName }}</view>
  19 + </template>
  20 + </uni-list-item>
  21 + </view>
  22 +
  23 + <!-- 产品 -->
  24 + <view class="section2">
  25 + <Product mode="view" :list="initDetailList" />
  26 + </view>
  27 +
  28 + <view class="title-header">
  29 + <image class="title-header_icon" src="/static/images/title.png" />
  30 + <span>本次试样概况</span>
  31 + </view>
  32 +
  33 + <view class="section">
  34 +
  35 + <uni-list-item title="表面">
  36 + <template v-slot:footer>
  37 + <uni-easyinput type="textarea" v-model="form.surface" placeholder="请输入表面" :inputBorder="false" />
  38 + </template>
  39 + </uni-list-item>
  40 +
  41 + <uni-list-item title="性能">
  42 + <template v-slot:footer>
  43 + <uni-easyinput type="textarea" v-model="form.performance" placeholder="请输入性能" :inputBorder="false" />
  44 + </template>
  45 + </uni-list-item>
  46 +
  47 + <uni-list-item title="公差">
  48 + <template v-slot:footer>
  49 + <uni-easyinput type="textarea" v-model="form.tolerance" placeholder="请输入公差" :inputBorder="false" />
  50 + </template>
  51 + </uni-list-item>
  52 + <uni-list-item title="带型">
  53 + <template v-slot:footer>
  54 + <uni-easyinput type="textarea" v-model="form.bandingPattern" placeholder="请输入带型" :inputBorder="false" />
  55 + </template>
  56 + </uni-list-item>
  57 +
  58 + <uni-list-item title="包装">
  59 + <template v-slot:footer>
  60 + <uni-easyinput type="textarea" v-model="form.packaging" placeholder="请输入包装" :inputBorder="false" />
  61 + </template>
  62 + </uni-list-item>
  63 +
  64 + <uni-list-item title="件重条头">
  65 + <template v-slot:footer>
  66 + <uni-easyinput type="textarea" v-model="form.weight" placeholder="请输入件重条头" :inputBorder="false" />
  67 + </template>
  68 + </uni-list-item>
  69 + <uni-list-item title="其他">
  70 + <template v-slot:footer>
  71 + <uni-easyinput type="textarea" v-model="form.other" placeholder="请输入其他" :inputBorder="false" />
  72 + </template>
  73 + </uni-list-item>
  74 +
  75 + <uni-list-item class="select-item" :class="form.sampleResultName ? 'is-filled' : 'is-empty'" clickable
  76 + @click="openSheet('sampleResult')" :rightText="form.sampleResultName || '请选择结论'" showArrow>
  77 + <template v-slot:body>
  78 + <view class="item-title"><text>结论</text></view>
  79 + </template>
  80 + </uni-list-item>
  81 + <uni-list-item class="select-item" :class="form.sampleResultSubName ? 'is-filled' : 'is-empty'" clickable
  82 + @click="openSheet('sampleResultSub')" :rightText="form.sampleResultSubName || '请选择'" showArrow>
  83 + <template v-slot:body>
  84 + <view class="item-title"><text></text></view>
  85 + </template>
  86 + </uni-list-item>
  87 +
  88 + <uni-list-item title="客户评价依据">
  89 + <template v-slot:footer>
  90 + <FileUpload v-model="customerReviewsFile" />
  91 + </template>
  92 + </uni-list-item>
  93 +
  94 + </view>
  95 +
  96 + <view class="footer">
  97 + <button class="btn submit" type="primary" @click="onSubmit">保存</button>
  98 + </view>
  99 + </uni-list>
  100 + </scroll-view>
  101 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
  102 + @confirm="onSheetConfirm" />
  103 + </view>
  104 +</template>
  105 +
  106 +<script>
  107 +import { updateApi, getDetailApi } from '@/api/follow_up_form.js'
  108 +import Product from './product.vue'
  109 +import SingleSelectSheet from '@/components/single-select/index.vue'
  110 +import {
  111 + getDicByCodes
  112 +} from '@/utils/dic'
  113 +import {
  114 + getDicName
  115 +} from '@/utils/dic.js'
  116 +import FileUpload from '@/components/file-upload/index.vue'
  117 +
  118 +export default {
  119 + name: 'FollowUpFormModify',
  120 + components: { Product, SingleSelectSheet, FileUpload },
  121 + data() {
  122 + return {
  123 + form: {
  124 + purchaseOrderId: '',
  125 + id: '',
  126 + // 订单基础信息
  127 + purchaseOrderName: '',
  128 + customerName: '',
  129 + customerId: '',
  130 + workshopName: '',
  131 + workshopId: '',
  132 + originPlanShipDate: '',
  133 + deptName: '',
  134 + deptId: '',
  135 + totalQuantity: '',
  136 + totalShippedQuantity: '',
  137 + totalSupplementaryQuantity: '',
  138 + code: '',
  139 + // 默认当前日期 格式为 yyyy-MM-dd
  140 + orderDate: new Date().toISOString().substring(0, 10),
  141 +
  142 + },
  143 + initDetailList: [],
  144 + maxDeliveryDate: new Date().toISOString().substring(0, 10),
  145 + sheet: { visible: false, title: '请选择', options: [], value: '', field: '' },
  146 + dicOptions: {
  147 + SAMPLE_RESULT: [],
  148 + SAMPLE_RESULT_SUB: []
  149 + },
  150 + sampleResultLocal: [],
  151 + sampleResultSubLocal: [],
  152 + customerReviewsFile: { id: '', name: '' },
  153 + }
  154 + },
  155 + onLoad(query) {
  156 + this.loadAllDicData()
  157 + const id = (query && (query.id || query.code)) || ''
  158 + if (id) {
  159 + this.loadDetail(id)
  160 + }
  161 + },
  162 + methods: {
  163 + getDicName,
  164 + async loadDetail(id) {
  165 + try {
  166 + const res = await getDetailApi(id)
  167 + const m = res.data || {}
  168 + const next = { ...this.form, ...m }
  169 + // 确保ID存在
  170 + next.id = m.id || id;
  171 + next.sampleResultName = this.sampleResultLocal.find(o => String(o.value) === String(next.sampleResult))?.label || ''
  172 + next.sampleResultSubName = this.sampleResultSubLocal.find(o => String(o.value) === String(next.sampleResultSub))?.label || ''
  173 +
  174 + this.customerReviewsFile = {
  175 + id: next.customerReviewsFileId || '',
  176 + name: next.customerReviewsFileName || ''
  177 + }
  178 + // 映射列表
  179 + // 注意:详情返回的是 detailList initDetailList 以便 Product 组件初始化
  180 + // 且需要处理字段兼容性,确保 Product 组件能正确显示和编辑
  181 + const lines = Array.isArray(m.detailList) ? m.detailList.map(x => ({
  182 + ...x,
  183 + // 确保 Product 组件需要的字段存在
  184 + // Product组件使用: quantity(需发), shippedQuantity(实发), supplementaryQuantity(需求补货), salesPrice(单价)
  185 + // 详情接口返回的字段应该已经包含了这些,如果有差异需要在此处转换
  186 + // 注意:add.vue中 onRelateConfirm 做了映射,这里是回显,通常直接使用即可
  187 + })) : []
  188 +
  189 + this.form = next;
  190 + this.initDetailList = lines;
  191 + } catch (e) {
  192 + uni.showToast({ title: '加载失败', icon: 'none' })
  193 + }
  194 + },
  195 + loadAllDicData() {
  196 + const dicCodes = ['SAMPLE_RESULT', 'SAMPLE_RESULT_SUB']
  197 + return getDicByCodes(dicCodes).then(results => {
  198 + this.dicOptions.SAMPLE_RESULT = results.SAMPLE_RESULT.data || []
  199 + this.dicOptions.SAMPLE_RESULT_SUB = results.SAMPLE_RESULT_SUB.data || []
  200 + this.sampleResultLocal = (this.dicOptions.SAMPLE_RESULT || []).map(it => ({
  201 + value: it.code,
  202 + label: it.name
  203 + }))
  204 + this.sampleResultSubLocal = (this.dicOptions.SAMPLE_RESULT_SUB || []).map(it => ({
  205 + value: it.code,
  206 + label: it.name
  207 + }))
  208 + }).catch(() => {
  209 + this.dicOptions = {
  210 + SAMPLE_RESULT: [],
  211 + SAMPLE_RESULT_SUB: []
  212 + }
  213 + this.sampleResultLocal = []
  214 + this.sampleResultSubLocal = []
  215 + })
  216 + },
  217 + validateRequired() {
  218 + // const checks = [
  219 + // { key: 'purchaseOrderName', label: '订单编号' }
  220 + // ]
  221 + // for (const it of checks) {
  222 + // const val = this.form[it.key]
  223 + // if (val === undefined || val === null || String(val).trim() === '') {
  224 + // uni.showToast({ title: `请先选择${it.label}`, icon: 'none' })
  225 + // return false
  226 + // }
  227 + // }
  228 + return true
  229 + },
  230 + validateLineListRequired() {
  231 + const list = Array.isArray(this.form.purchaseOrderLineList) ? this.form.purchaseOrderLineList : []
  232 + if (list.length === 0) {
  233 + uni.showToast({ title: '请先添加产品', icon: 'none' })
  234 + return false
  235 + }
  236 + const fields = [
  237 + { key: 'brand', label: '牌号' },
  238 + { key: 'quantity', label: '需发' },
  239 + { key: 'supplementaryQuantity', label: '需求补货' },
  240 + ]
  241 + for (let i = 0; i < list.length; i++) {
  242 + const it = list[i] || {}
  243 + for (const f of fields) {
  244 + const v = it && it[f.key]
  245 + if (v === undefined || v === null || String(v).trim() === '') {
  246 + uni.showToast({ title: `产品第${i + 1}条:${f.label}不能为空!`, icon: 'none' })
  247 + return false
  248 + }
  249 + }
  250 + const has = (v) => v !== undefined && v !== null && String(v).trim() !== ''
  251 + if (has(it.thicknessTolPos) && has(it.thicknessTolNeg)) {
  252 + const pos = Number(it.thicknessTolPos)
  253 + const neg = Number(it.thicknessTolNeg)
  254 + if (!(pos > neg)) {
  255 + uni.showToast({ title: `产品第${i + 1}条:厚度公差上限需大于下限`, icon: 'none' })
  256 + return false
  257 + }
  258 + }
  259 + if (has(it.widthTolPos) && has(it.widthTolNeg)) {
  260 + const pos = Number(it.widthTolPos)
  261 + const neg = Number(it.widthTolNeg)
  262 + if (!(pos > neg)) {
  263 + uni.showToast({ title: `产品第${i + 1}条:宽度公差上限需大于下限`, icon: 'none' })
  264 + return false
  265 + }
  266 + }
  267 + if (has(it.lengthTolPos) && has(it.lengthTolNeg)) {
  268 + const pos = Number(it.lengthTolPos)
  269 + const neg = Number(it.lengthTolNeg)
  270 + if (!(pos > neg)) {
  271 + uni.showToast({ title: `产品第${i + 1}条:长度公差上限需大于下限`, icon: 'none' })
  272 + return false
  273 + }
  274 + }
  275 + }
  276 + return true
  277 + },
  278 + async onSubmit() {
  279 + if (!this.validateRequired()) return
  280 + const payload = { ...this.form }
  281 + delete payload.status
  282 + payload.customerReviewsFileId = this.customerReviewsFile.id || '';
  283 + payload.customerReviewsFileName = this.customerReviewsFile.name || '';
  284 + console.log('onSubmit__payload', payload)
  285 + try {
  286 + await updateApi(payload)
  287 + uni.showToast({ title: '保存成功', icon: 'success' })
  288 + setTimeout(() => { uni.redirectTo({ url: '/pages/follow_up_form/index' }) }, 300)
  289 + } catch (e) {
  290 + uni.showToast({ title: (e && e.msg) || '保存失败', icon: 'none' })
  291 + }
  292 + },
  293 + calculateSummary(list) {
  294 + const summary = (list || []).reduce((acc, it) => {
  295 + const qty = Number(it.supplementaryQuantity) || 0
  296 + const shipped = Number(it.shippedQuantity) || 0
  297 + const orderQty = Number(it.quantity) || 0
  298 + acc.totalSupplementaryQuantity += qty
  299 + acc.totalShippedQuantity += shipped
  300 + acc.totalQuantity += orderQty
  301 + return acc
  302 + }, { totalQuantity: 0, totalShippedQuantity: 0, totalSupplementaryQuantity: 0 })
  303 +
  304 + const fixedTotalQuantity = Number(summary.totalQuantity.toFixed(2))
  305 + const fixedTotalShippedQuantity = Number(summary.totalShippedQuantity.toFixed(2))
  306 + const fixedTotalSupplementaryQuantity = Number(summary.totalSupplementaryQuantity.toFixed(2))
  307 + this.form.totalQuantity = fixedTotalQuantity
  308 + this.form.totalShippedQuantity = fixedTotalShippedQuantity
  309 + this.form.totalSupplementaryQuantity = fixedTotalSupplementaryQuantity
  310 + },
  311 + purchaseOrderLineListChange(data) {
  312 + const list = Array.isArray(data) ? data : []
  313 + this.form.productSampleConfirmationSlipDetailList = list
  314 + },
  315 + openSheet(field) {
  316 + let options = []
  317 + let title = ''
  318 + let value = ''
  319 +
  320 + if (field === 'sampleResult') {
  321 + title = '结论'
  322 + options = this.sampleResultLocal
  323 + value = this.form.sampleResult
  324 + } else if (field === 'sampleResultSub') {
  325 + if (!this.form.sampleResult) {
  326 + uni.showToast({ title: '请先选择结论', icon: 'none' })
  327 + return
  328 + }
  329 + title = '请选择'
  330 + options = this.sampleResultSubLocal.filter(o => {
  331 + const code = o.value
  332 + return code && this.form.sampleResult && String(code).startsWith(String(this.form.sampleResult))
  333 + })
  334 + value = this.form.sampleResultSub
  335 + }
  336 + const match = options.find(o => String(o.value) === String(value))
  337 + this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
  338 + },
  339 + onSheetConfirm({ value, label }) {
  340 + const field = this.sheet.field
  341 + if (field === 'sampleResult') {
  342 + this.form.sampleResultSub = '';
  343 + this.form.sampleResultSubName = '';
  344 + }
  345 + this.form[field] = value
  346 + this.form[field + 'Name'] = label
  347 + this.sheet.visible = false
  348 + },
  349 + }
  350 +}
  351 +</script>
  352 +
  353 +<style lang="scss" scoped>
  354 +.page {
  355 + display: flex;
  356 + flex-direction: column;
  357 + height: 100%;
  358 +}
  359 +
  360 +.scroll {
  361 + flex: 1;
  362 + padding: 6rpx 0 144rpx;
  363 +}
  364 +
  365 +
  366 +
  367 +.title-header {
  368 + background-color: #fff;
  369 + display: flex;
  370 + align-items: center;
  371 + padding: 32rpx 32rpx 22rpx;
  372 +
  373 + .title-header_icon {
  374 + width: 32rpx;
  375 + height: 28rpx;
  376 + margin-right: 16rpx;
  377 + }
  378 +
  379 + span {
  380 + color: rgba(0, 0, 0, 0.9);
  381 + font-size: 32rpx;
  382 + line-height: 44rpx;
  383 + font-weight: 600;
  384 + }
  385 +}
  386 +
  387 +
  388 +.section {
  389 + background: #fff;
  390 + margin-bottom: 20rpx;
  391 +}
  392 +
  393 +.section2 {
  394 + background: #f1f1f1;
  395 + margin-bottom: 20rpx;
  396 +}
  397 +
  398 +::v-deep .uni-list {
  399 + background: transparent;
  400 +
  401 + &-item {
  402 + &__extra-text {
  403 + font-size: 32rpx;
  404 + }
  405 +
  406 + &__content-title {
  407 + font-size: 32rpx;
  408 + color: rgba(0, 0, 0, 0.9);
  409 + }
  410 +
  411 + &__container {
  412 + padding: 32rpx;
  413 + // align-items: center;
  414 +
  415 + .uni-easyinput {
  416 +
  417 + .is-disabled {
  418 + background-color: transparent !important;
  419 + }
  420 +
  421 + &__placeholder-class {
  422 + font-size: 32rpx;
  423 + color: rgba(0, 0, 0, 0.4);
  424 + }
  425 +
  426 + &__content {
  427 + border: none;
  428 +
  429 + &-input {
  430 + padding-left: 0 !important;
  431 + height: 48rpx;
  432 + line-height: 48rpx;
  433 + font-size: 32rpx;
  434 + }
  435 +
  436 + .content-clear-icon {
  437 + font-size: 44rpx !important;
  438 + }
  439 + }
  440 + }
  441 +
  442 + .amount-row {
  443 + flex: 1;
  444 + display: flex;
  445 + align-items: center;
  446 +
  447 + .uni-easyinput {
  448 + flex: 1;
  449 + }
  450 +
  451 + .unit {
  452 + margin-left: 16rpx;
  453 + color: rgba(0, 0, 0, 0.9);
  454 + }
  455 + }
  456 +
  457 + .item-title,
  458 + .uni-list-item__content {
  459 + flex: none;
  460 + min-height: 48rpx;
  461 + line-height: 48rpx;
  462 + font-size: 32rpx;
  463 + position: relative;
  464 + width: 210rpx;
  465 + margin-right: 32rpx;
  466 + color: rgba(0, 0, 0, 0.9);
  467 + padding-right: 0;
  468 +
  469 +
  470 + .required {
  471 + color: red;
  472 + position: absolute;
  473 + top: 50%;
  474 + transform: translateY(-50%);
  475 + left: -16rpx;
  476 + }
  477 + }
  478 +
  479 + }
  480 +
  481 + &.select-item {
  482 + &.is-empty {
  483 + .uni-list-item__extra-text {
  484 + color: rgba(0, 0, 0, 0.4) !important;
  485 + }
  486 + }
  487 +
  488 + &.is-filled {
  489 + .uni-list-item__extra-text {
  490 + color: rgba(0, 0, 0, 0.9) !important;
  491 + }
  492 + }
  493 +
  494 + .serial-number-row {
  495 + display: flex;
  496 + align-items: center;
  497 + }
  498 +
  499 + }
  500 +
  501 + &.mgb10 {
  502 + margin-bottom: 20rpx;
  503 + }
  504 +
  505 + }
  506 +
  507 + .title-header {
  508 + background-color: #fff;
  509 + display: flex;
  510 + align-items: center;
  511 + padding: 32rpx 32rpx 22rpx;
  512 +
  513 + &_icon {
  514 + width: 32rpx;
  515 + height: 28rpx;
  516 + margin-right: 16rpx;
  517 + }
  518 +
  519 + span {
  520 + color: rgba(0, 0, 0, 0.9);
  521 + font-size: 32rpx;
  522 + line-height: 44rpx;
  523 + font-weight: 600;
  524 + }
  525 + }
  526 +}
  527 +
  528 +/* 只读 easyinput 根据内容自适应高度 */
  529 +::v-deep .uni-list-item__container {
  530 + align-items: flex-start;
  531 +}
  532 +
  533 +/* 只读文本样式 */
  534 +.readonly-text {
  535 + color: rgba(0, 0, 0, 0.9);
  536 + font-size: 32rpx;
  537 + line-height: 48rpx;
  538 + text-align: right;
  539 + white-space: pre-wrap;
  540 + word-break: break-all;
  541 +}
  542 +
  543 +.footer {
  544 + position: fixed;
  545 + left: 0;
  546 + right: 0;
  547 + bottom: 0;
  548 + padding: 32rpx;
  549 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  550 + background: #fff;
  551 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  552 + z-index: 10;
  553 +
  554 + .btn {
  555 + height: 80rpx;
  556 + line-height: 80rpx;
  557 + border-radius: 12rpx;
  558 + font-size: 32rpx;
  559 + }
  560 +
  561 + .submit {
  562 + background: $theme-primary;
  563 + color: #fff;
  564 + }
  565 +}
  566 +</style>
  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 + <view class="row"><text class="label">牌号</text><text class="value">{{ item.brand }}</text></view>
  21 + <!-- 厚(公差) * 宽(公差) * 长(公差) -->
  22 + <view class="row row-spec"><text class="label">规格(mm)</text>
  23 + <view class="value value-spec">
  24 + <view v-if="item.thickness" class="value-spec_val">{{ item.thickness }}</view>
  25 + <view v-if="item.thickness" class="value-spec_box">
  26 + <view v-if="item.thicknessTolPos" class="value-spec_box_1">{{ item.thicknessTolPos > 0 ? '+' + item.thicknessTolPos : item.thicknessTolPos }}
  27 + </view>
  28 + <view v-if="item.thicknessTolNeg" class="value-spec_box_2">{{ item.thicknessTolNeg > 0 ? '+' + item.thicknessTolNeg : item.thicknessTolNeg }}
  29 + </view>
  30 + </view>
  31 + <view v-if="item.width" class="value-spec_val p12">*</view>
  32 + <view v-if="item.width" class="value-spec_val">{{ item.width }}</view>
  33 + <view v-if="item.width" class="value-spec_box">
  34 + <view v-if="item.widthTolPos" class="value-spec_box_1">{{ item.widthTolPos > 0 ? '+' +
  35 + item.widthTolPos : item.widthTolPos }}</view>
  36 + <view v-if="item.widthTolNeg" class="value-spec_box_2">{{ item.widthTolNeg > 0 ? '+' +
  37 + item.widthTolNeg : item.widthTolNeg }}</view>
  38 + </view>
  39 + <view v-if="item.length" class="value-spec_val p12">*</view>
  40 + <view v-if="item.length" class="value-spec_val">{{ item.length }}</view>
  41 + <view v-if="item.length" class="value-spec_box">
  42 + <view v-if="item.lengthTolPos" class="value-spec_box_1">{{ item.lengthTolPos > 0 ? '+' +
  43 + item.lengthTolPos : item.lengthTolPos }}</view>
  44 + <view v-if="item.lengthTolNeg" class="value-spec_box_2">{{ item.lengthTolNeg > 0 ? '+' +
  45 + item.lengthTolNeg : item.lengthTolNeg }}</view>
  46 + </view>
  47 + </view>
  48 + </view>
  49 + <view class="row"><text class="label">状态</text><text class="value">{{ item.status }}</text></view>
  50 + <view v-show="!item.collapsed">
  51 +
  52 + <view class="row" :class="{ 'noneStyle': !item.showSalesPrice }"><text
  53 + class="label">数量kg</text><text class="value">{{ item.quantity }}</text>
  54 + </view>
  55 +
  56 + <uni-list class="edit-list">
  57 + <uni-list-item class="select-item"
  58 + :class="item.provideSamplesName ? 'is-filled' : 'is-empty'" clickable
  59 + @click="openProductSheet(idx, 'provideSamples')"
  60 + :rightText="item.provideSamplesName || '请选择是否提供样品'" showArrow>
  61 + <template v-slot:body>
  62 + <view class="item-title"><text>是否提供样品</text></view>
  63 + </template>
  64 + </uni-list-item>
  65 + <uni-list-item class="select-item"
  66 + :class="item.clearParametersName ? 'is-filled' : 'is-empty'" clickable
  67 + @click="openProductSheet(idx, 'clearParameters')"
  68 + :rightText="item.clearParametersName || '请选择是否提供明确参数'" showArrow>
  69 + <template v-slot:body>
  70 + <view class="item-title"><text>是否提供明确参数</text></view>
  71 + </template>
  72 + </uni-list-item>
  73 + </uni-list>
  74 + </view>
  75 +
  76 + <view class="block-ops">
  77 + <div class="toggle" @click="toggleItem(idx)">
  78 + <image :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'"
  79 + class="icon" />
  80 + {{ item.collapsed ? '展开' : '收起' }}
  81 + </div>
  82 + </view>
  83 + </view>
  84 + </view>
  85 +
  86 + <view v-else-if="mode === 'view'" class="view-list" v-show="!collapsedView">
  87 + <view v-for="(item, idx) in items" :key="'v-' + idx" class="card">
  88 + <view class="row"><text class="label">牌号</text><text class="value">{{ item.brand }}</text></view>
  89 + <!-- 厚(公差) * 宽(公差) * 长(公差) -->
  90 + <view class="row row-spec"><text class="label">规格(mm)</text>
  91 + <view class="value value-spec">
  92 + <view v-if="item.thickness" class="value-spec_val">{{ item.thickness }}</view>
  93 + <view v-if="item.thickness" class="value-spec_box">
  94 + <view v-if="item.thicknessTolPos" class="value-spec_box_1">{{ item.thicknessTolPos > 0 ? '+'
  95 + +
  96 + item.thicknessTolPos : item.thicknessTolPos }}
  97 + </view>
  98 + <view v-if="item.thicknessTolNeg" class="value-spec_box_2">{{ item.thicknessTolNeg > 0 ? '+'
  99 + +
  100 + item.thicknessTolNeg : item.thicknessTolNeg }}
  101 + </view>
  102 + </view>
  103 + <view v-if="item.width" class="value-spec_val p12">*</view>
  104 + <view v-if="item.width" class="value-spec_val">{{ item.width }}</view>
  105 + <view v-if="item.width" class="value-spec_box">
  106 + <view v-if="item.widthTolPos" class="value-spec_box_1">{{ item.widthTolPos > 0 ? '+' +
  107 + item.widthTolPos : item.widthTolPos }}
  108 + </view>
  109 + <view v-if="item.widthTolNeg" class="value-spec_box_2">{{ item.widthTolNeg > 0 ? '+' +
  110 + item.widthTolNeg : item.widthTolNeg }}
  111 + </view>
  112 + </view>
  113 + <view v-if="item.length" class="value-spec_val p12">*</view>
  114 + <view v-if="item.length" class="value-spec_val">{{ item.length }}</view>
  115 + <view v-if="item.length" class="value-spec_box">
  116 + <view v-if="item.lengthTolPos" class="value-spec_box_1">{{ item.lengthTolPos > 0 ? '+' +
  117 + item.lengthTolPos : item.lengthTolPos }}
  118 + </view>
  119 + <view v-if="item.lengthTolNeg" class="value-spec_box_2">{{ item.lengthTolNeg > 0 ? '+' +
  120 + item.lengthTolNeg : item.lengthTolNeg }}
  121 + </view>
  122 + </view>
  123 + </view>
  124 + </view>
  125 + <view class="row"><text class="label">状态</text><text class="value">{{ item.status }}</text></view>
  126 + <view class="row"><text class="label">发货日期</text><text class="value">{{ item.shipmentDate }}</text></view>
  127 + <view class="row"><text class="label">数量(kg)</text><text class="value">{{ item.quantity }}</text></view>
  128 + <view class="row"><text class="label">产量批次号</text><text class="value">{{ item.yieldBatchNo }}</text></view>
  129 + </view>
  130 + </view>
  131 +
  132 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" />
  133 + </view>
  134 +</template>
  135 +<script>
  136 +import { uuid } from '@/utils/uuid.js'
  137 +import SingleSelectSheet from '@/components/single-select/index.vue'
  138 +export default {
  139 + name: 'Product',
  140 + props: {
  141 + title: { type: String, default: '' },
  142 + mode: { type: String, default: 'add' },
  143 + list: { type: Array, default: () => [] },
  144 + max: { type: Number, default: 8 },
  145 + provideSamplesOptions: { type: Array, default: () => [] },
  146 + clearParametersOptions: { type: Array, default: () => [] },
  147 + },
  148 + components: { SingleSelectSheet },
  149 + data() {
  150 + return {
  151 + items: [],
  152 + collapsedView: false,
  153 + roleCodes: [],
  154 + sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1, mode: '' }
  155 + }
  156 + },
  157 + computed: {
  158 + minDeliveryDate() {
  159 + const s = this.orderDate
  160 + if (!s) return ''
  161 + const parts = String(s).split('-')
  162 + const y = Number(parts[0])
  163 + const m = Number(parts[1])
  164 + const d = Number(parts[2])
  165 + if (!y || !m || !d) return ''
  166 + const dt = new Date(y, m - 1, d)
  167 + dt.setDate(dt.getDate() + 1)
  168 + const yy = dt.getFullYear()
  169 + const mm = String(dt.getMonth() + 1).padStart(2, '0')
  170 + const dd = String(dt.getDate()).padStart(2, '0')
  171 + return `${yy}/${mm}/${dd}`
  172 + },
  173 + // roleCodes() {
  174 + // const g = this.$store && this.$store.getters
  175 + // return (g && g.roleCodes) || [];
  176 + // },
  177 + },
  178 + watch: {
  179 + items: {
  180 + handler() { this.emitChange() },
  181 + deep: true
  182 + },
  183 + list: {
  184 + handler(v) {
  185 + const arr = Array.isArray(v) ? v : []
  186 + this.items = arr.map(x => {
  187 + const it = { ...this.defaultItem(), ...x, collapsed: true }
  188 + return it
  189 + })
  190 + },
  191 + deep: true
  192 + },
  193 + },
  194 + created() {
  195 + const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, collapsed: false })) : [{ ...this.defaultItem(), collapsed: false }]
  196 + this.items = init;
  197 + },
  198 + methods: {
  199 + defaultItem() {
  200 + return {
  201 + purchaseOrderId: uuid(),
  202 + collapsed: false,
  203 + id: '',
  204 + // 厚度公差
  205 + thicknessTolPos: '',
  206 + thicknessTolNeg: '',
  207 + // 宽度公差
  208 + widthTolPos: '',
  209 + widthTolNeg: '',
  210 + // 长度公差
  211 + lengthTolPos: '',
  212 + lengthTolNeg: '',
  213 + // 其他字段
  214 + industry: '',
  215 + quality: '',
  216 + brand: '',
  217 + thickness: '',
  218 + width: '',
  219 + length: '',
  220 + status: '',
  221 + quantity: '',
  222 + shippedQuantity: '',
  223 + supplementaryQuantity: '',
  224 + confirmedDeliveryDate: '',
  225 + remarks: '',
  226 + }
  227 + },
  228 +
  229 + onAdd() {
  230 + const obj = this.defaultItem()
  231 + obj.collapsed = true
  232 + this.items.push(obj)
  233 + this.emitChange()
  234 + },
  235 + onRemove(id) {
  236 + if (!id) return
  237 + uni.showModal({
  238 + title: '系统提示',
  239 + content: '是否确定删除选中的产品?',
  240 + confirmText: '确定',
  241 + cancelText: '取消',
  242 + success: (res) => {
  243 + if (res && res.confirm) {
  244 + const i = this.items.findIndex(it => String(it.purchaseOrderId) === String(id))
  245 + if (i >= 0) {
  246 + this.items.splice(i, 1)
  247 + this.emitChange()
  248 + }
  249 + }
  250 + }
  251 + })
  252 + },
  253 + toggleItem(idx) {
  254 + const it = this.items[idx]
  255 + if (!it) return
  256 + it.collapsed = !it.collapsed
  257 + this.$set(this.items, idx, it)
  258 + },
  259 + emitChange() {
  260 + const out = this.items.map(it => ({ ...it }))
  261 + this.$emit('input', out)
  262 + this.$emit('update:value', out)
  263 + this.$emit('change', out)
  264 + },
  265 + onNonNegativeNumberInput(val, item, idx, field) {
  266 + let v = String(val != null ? val : (item && item[field]) || '')
  267 + v = v.replace(/[^0-9.]/g, '')
  268 + v = v.replace(/(\..*)\./g, '$1')
  269 + if (v.startsWith('.')) v = '0' + v
  270 + if (v === '') { item[field] = ''; if (typeof idx === 'number') this.$set(this.items, idx, { ...item }); return }
  271 + const num = Number(v)
  272 + if (isNaN(num) || num < 0) {
  273 + item[field] = '0'
  274 + } else {
  275 + item[field] = v
  276 + }
  277 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  278 + },
  279 + onNonNegativeNumberBlur(item, idx, field) {
  280 + const v = String((item && item[field]) || '')
  281 + const num = Number(v)
  282 + if (isNaN(num) || num < 0) item[field] = '0'
  283 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  284 + },
  285 + onRealNumberInput(val, item, idx, field) {
  286 + let s = String(val != null ? val : (item && item[field]) || '')
  287 + const neg = s.trim().startsWith('-')
  288 + s = s.replace(/[^0-9.\-]/g, '')
  289 + s = s.replace(/(?!^)-/g, '')
  290 + s = s.replace(/(\..*)\./g, '$1')
  291 + if (s.startsWith('.')) s = '0' + s
  292 + if (s.startsWith('-.')) s = '-0.' + s.slice(2)
  293 + if (neg && !s.startsWith('-')) s = '-' + s.replace(/-/g, '')
  294 + item[field] = s
  295 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  296 + },
  297 + onRealNumberBlur(item, idx, field) {
  298 + const s = String((item && item[field]) || '')
  299 + if (s === '') { if (typeof idx === 'number') this.$set(this.items, idx, { ...item }); return }
  300 + const n = Number(s)
  301 + if (isNaN(n)) item[field] = ''
  302 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  303 + },
  304 + // 限制输入为2位小数
  305 + onTwoDecimalInput(val, item, idx, field) {
  306 + let v = String(val != null ? val : (item && item[field]) || '')
  307 + v = v.replace(/[^0-9.]/g, '')
  308 + v = v.replace(/(\..*)\./g, '$1')
  309 +
  310 + // Restrict to 2 decimal places
  311 + const decimalIndex = v.indexOf('.')
  312 + if (decimalIndex !== -1 && v.length > decimalIndex + 3) {
  313 + v = v.substring(0, decimalIndex + 3)
  314 + }
  315 +
  316 + if (v.startsWith('.')) v = '0' + v
  317 +
  318 + // If the value was modified (truncated or cleaned)
  319 + if (String(val) !== v) {
  320 + // Hack: Temporarily set the dirty value to trigger Vue update mechanism
  321 + // This ensures that when we set the clean value back, Vue detects a change
  322 + item[field] = val
  323 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  324 +
  325 + // Then revert to the clean value asynchronously
  326 + setTimeout(() => {
  327 + item[field] = v
  328 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  329 + }, 0)
  330 + } else {
  331 + item[field] = v
  332 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  333 + }
  334 + },
  335 + onTwoDecimalBlur(item, idx, field) {
  336 + let v = String((item && item[field]) || '')
  337 + const num = Number(v)
  338 + if (isNaN(num) || num < 0) {
  339 + item[field] = '0'
  340 + } else {
  341 + if (v.endsWith('.')) {
  342 + item[field] = v.slice(0, -1)
  343 + }
  344 + }
  345 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  346 + },
  347 + toggleViewCollapse() {
  348 + this.collapsedView = !this.collapsedView
  349 + },
  350 + onDeliveryChange(e, item, idx) {
  351 + const getStr = (x) => {
  352 + if (x && x.detail && x.detail.value !== undefined) return x.detail.value
  353 + if (typeof x === 'string') return x
  354 + return item && item.deliveryDate ? item.deliveryDate : ''
  355 + }
  356 + const val = getStr(e)
  357 + if (!val || !this.orderDate) return
  358 + const parse = (s) => {
  359 + const p = String(s).replace(/\//g, '-').split('-')
  360 + const y = Number(p[0])
  361 + const m = Number(p[1])
  362 + const d = Number(p[2])
  363 + return new Date(y, m - 1, d)
  364 + }
  365 + const sel = parse(val)
  366 + const ord = parse(this.orderDate)
  367 + if (!(sel > ord)) {
  368 + item.deliveryDate = ''
  369 + this.$set(this.items, idx, { ...item })
  370 + uni.showToast({ title: '发货日期必须大于订货日期', icon: 'none' })
  371 + }
  372 + },
  373 + openProductSheet(idx, mode = 'provideSamples') {
  374 + let opts = []
  375 + let title = ''
  376 + let value = ''
  377 + const item = this.items[idx]
  378 +
  379 + if (mode === 'provideSamples') {
  380 + opts = this.provideSamplesOptions
  381 + value = item.provideSamples
  382 + title = '选择是否提供样品'
  383 + } else if (mode === 'clearParameters') {
  384 + opts = this.clearParametersOptions;
  385 + value = item.clearParameters
  386 + title = '是否提供明确参数'
  387 + }
  388 + console.log('____', { ...this.sheet, visible: true, title, options: opts, idx, value, mode })
  389 + this.sheet = { ...this.sheet, visible: true, title, options: opts, idx, value, mode }
  390 + },
  391 + onProductConfirm({ value, label }) {
  392 + const idx = this.sheet.idx
  393 + const _mode = this.sheet.mode;
  394 + const it = this.items[idx]
  395 + if (!it) { this.sheet.visible = false; return }
  396 + it[_mode] = value
  397 + it[_mode + 'Name'] = label || ''
  398 + this.$set(this.items, idx, it)
  399 + this.sheet.visible = false
  400 + this.emitChange()
  401 + },
  402 + }
  403 +}
  404 +</script>
  405 +<style lang="scss" scoped>
  406 +.header {
  407 + background-color: #fff;
  408 + display: flex;
  409 + align-items: center;
  410 + padding: 24rpx 32rpx;
  411 +
  412 + &.bp {
  413 + border-bottom: 1px solid #f0f0f0;
  414 + }
  415 +}
  416 +
  417 +.dot {
  418 + width: 16rpx;
  419 + height: 16rpx;
  420 + background: #3D48A3;
  421 + border-radius: 50%;
  422 + margin-right: 12rpx;
  423 +}
  424 +
  425 +.title {
  426 + font-size: 32rpx;
  427 + color: rgba(0, 0, 0, 0.9);
  428 + font-weight: 600;
  429 +}
  430 +
  431 +.ops {
  432 + margin-left: auto;
  433 +}
  434 +
  435 +.op {
  436 + color: $theme-primary;
  437 + font-size: 28rpx;
  438 + margin-left: 8rpx;
  439 +}
  440 +
  441 +.op1 {
  442 + display: flex;
  443 + align-items: center;
  444 +}
  445 +
  446 +.opAdd {
  447 + color: rgba(0, 0, 0, 0.6);
  448 + width: 40rpx;
  449 + height: 40rpx;
  450 +}
  451 +
  452 +.opCollapse {
  453 + color: rgba(0, 0, 0, 0.6);
  454 + width: 32rpx;
  455 + height: 28rpx;
  456 + margin-right: 16rpx;
  457 +}
  458 +
  459 +::v-deep .uni-list {
  460 + background: transparent;
  461 +
  462 + .uni-list--border-top {
  463 + background-color: transparent !important;
  464 + }
  465 +
  466 + &-item {
  467 + &__extra-text {
  468 + font-size: 32rpx;
  469 + }
  470 +
  471 + &__content-title {
  472 + font-size: 32rpx;
  473 + color: rgba(0, 0, 0, 0.9);
  474 + }
  475 +
  476 + &__container {
  477 + padding: 32rpx;
  478 +
  479 + .uni-easyinput {
  480 +
  481 + .is-disabled {
  482 + background-color: transparent !important;
  483 + }
  484 +
  485 + &__placeholder-class {
  486 + font-size: 32rpx;
  487 + color: rgba(0, 0, 0, 0.4);
  488 + }
  489 +
  490 + &__content {
  491 + border: none;
  492 +
  493 + &-input {
  494 + padding-left: 0 !important;
  495 + height: 48rpx;
  496 + line-height: 48rpx;
  497 + font-size: 32rpx;
  498 + }
  499 +
  500 + .content-clear-icon {
  501 + font-size: 44rpx !important;
  502 + }
  503 + }
  504 + }
  505 +
  506 + .amount-row {
  507 + flex: 1;
  508 + display: flex;
  509 + align-items: center;
  510 +
  511 + .uni-easyinput {
  512 + flex: 1;
  513 + }
  514 +
  515 + .unit {
  516 + margin-left: 16rpx;
  517 + color: rgba(0, 0, 0, 0.9);
  518 + }
  519 + }
  520 +
  521 + .item-title,
  522 + .uni-list-item__content {
  523 + flex: none;
  524 + min-height: 48rpx;
  525 + line-height: 48rpx;
  526 + font-size: 32rpx;
  527 + position: relative;
  528 + width: 210rpx;
  529 + margin-right: 32rpx;
  530 + color: rgba(0, 0, 0, 0.9);
  531 + padding-right: 0;
  532 +
  533 +
  534 + .required {
  535 + color: red;
  536 + position: absolute;
  537 + top: 50%;
  538 + transform: translateY(-50%);
  539 + left: -16rpx;
  540 + }
  541 + }
  542 +
  543 + }
  544 +
  545 + &.select-item {
  546 + &.is-empty {
  547 + .uni-list-item__extra-text {
  548 + color: rgba(0, 0, 0, 0.4) !important;
  549 + }
  550 + }
  551 +
  552 + &.is-filled {
  553 + .uni-list-item__extra-text {
  554 + color: rgba(0, 0, 0, 0.9) !important;
  555 + }
  556 + }
  557 +
  558 + .serial-number-row {
  559 + display: flex;
  560 + align-items: center;
  561 + }
  562 +
  563 + }
  564 +
  565 + &.mgb10 {
  566 + margin-bottom: 20rpx;
  567 + }
  568 +
  569 + }
  570 +
  571 + .title-header {
  572 + background-color: #fff;
  573 + display: flex;
  574 + align-items: center;
  575 + padding: 32rpx 32rpx 22rpx;
  576 +
  577 + &_icon {
  578 + width: 32rpx;
  579 + height: 28rpx;
  580 + margin-right: 16rpx;
  581 + }
  582 +
  583 + span {
  584 + color: rgba(0, 0, 0, 0.9);
  585 + font-size: 32rpx;
  586 + line-height: 44rpx;
  587 + font-weight: 600;
  588 + }
  589 + }
  590 +}
  591 +
  592 +/* 只读 easyinput 根据内容自适应高度 */
  593 +::v-deep .uni-list-item__container {
  594 + align-items: flex-start;
  595 +}
  596 +
  597 +.block-ops {
  598 + display: flex;
  599 + padding: 20rpx 32rpx 20rpx;
  600 + justify-content: space-around;
  601 +}
  602 +
  603 +.del {
  604 + color: #D54941;
  605 + font-size: 28rpx;
  606 + display: flex;
  607 + align-items: center;
  608 +
  609 + image {
  610 + width: 40rpx;
  611 + height: 40rpx;
  612 + }
  613 +}
  614 +
  615 +.toggle {
  616 + color: $theme-primary;
  617 + font-size: 28rpx;
  618 + display: flex;
  619 + align-items: center;
  620 +
  621 + image {
  622 + width: 40rpx;
  623 + height: 40rpx;
  624 + }
  625 +}
  626 +
  627 +.section {
  628 + background: #f1f1f1;
  629 + margin-bottom: 20rpx;
  630 +
  631 + .block {
  632 + background: #ffffff;
  633 + // padding: 32rpx 0;
  634 + margin-bottom: 20rpx;
  635 +
  636 + &:last-child {
  637 + margin-bottom: 0;
  638 + }
  639 + }
  640 +
  641 + .row {
  642 + display: flex;
  643 + // margin-bottom: 24rpx;
  644 + line-height: 32rpx;
  645 + padding: 32rpx;
  646 + border-bottom: 1rpx solid #f2f2f2 !important;
  647 +
  648 +
  649 + &.noneStyle {
  650 + border-bottom: 0;
  651 + border-bottom: none;
  652 + }
  653 +
  654 + &.row-spec {
  655 + align-items: center;
  656 + }
  657 + }
  658 +
  659 + .row:last-child {
  660 + margin-bottom: 0;
  661 + }
  662 +
  663 + .label {
  664 + width: 210rpx;
  665 + margin-right: 32rpx;
  666 + color: rgba(0, 0, 0, 0.9);
  667 + font-size: 32rpx;
  668 + line-height: 48rpx;
  669 + }
  670 +
  671 + .value {
  672 + flex: 1;
  673 + color: rgba(0, 0, 0, 0.9);
  674 + font-size: 32rpx;
  675 + white-space: pre-wrap;
  676 + word-break: break-all;
  677 + line-height: 48rpx;
  678 + }
  679 +
  680 + .value-spec {
  681 + height: 48rpx;
  682 + display: flex;
  683 + align-items: center;
  684 + color: #000000;
  685 +
  686 + &_box {
  687 + position: relative;
  688 + width: 60rpx;
  689 + height: 48rpx;
  690 +
  691 + &_1 {
  692 + font-size: 16rpx;
  693 + position: absolute;
  694 + top: -10rpx;
  695 + left: 0;
  696 + }
  697 +
  698 + &_2 {
  699 + font-size: 16rpx;
  700 + position: absolute;
  701 + bottom: -10rpx;
  702 + left: 0;
  703 + }
  704 + }
  705 +
  706 + &_val {
  707 + font-size: 28rpx;
  708 +
  709 + &.p12 {
  710 + padding-right: 12rpx;
  711 + }
  712 + }
  713 + }
  714 +
  715 + .view-total {
  716 + padding-top: 20rpx;
  717 +
  718 + .head {
  719 + font-size: 32rpx;
  720 + font-weight: 600;
  721 + line-height: 50rpx;
  722 + color: rgba(0, 0, 0, 0.9);
  723 + padding-bottom: 16rpx;
  724 + margin-bottom: 24rpx;
  725 + border-bottom: 1px dashed #E7E7E7;
  726 + }
  727 +
  728 + .row {
  729 + display: flex;
  730 + margin-bottom: 24rpx;
  731 + line-height: 32rpx;
  732 +
  733 + .label {
  734 + width: 180rpx;
  735 + margin-right: 14rpx;
  736 + color: rgba(0, 0, 0, 0.6);
  737 + font-size: 28rpx;
  738 + }
  739 +
  740 + .value {
  741 + flex: 1;
  742 + color: rgba(0, 0, 0, 0.9);
  743 + font-size: 28rpx;
  744 + white-space: pre-wrap;
  745 + word-break: break-all;
  746 + }
  747 + }
  748 + }
  749 +}
  750 +
  751 +
  752 +.view-list {
  753 + padding: 26rpx 32rpx;
  754 + background: #ffffff;
  755 +
  756 + .card {
  757 + background: #f3f3f3;
  758 + border-radius: 16rpx;
  759 + padding: 32rpx 44rpx;
  760 + margin-bottom: 20rpx;
  761 +
  762 + &:last-child {
  763 + margin-bottom: 0;
  764 + }
  765 + }
  766 +
  767 + .row {
  768 + display: flex;
  769 + margin-bottom: 24rpx;
  770 + line-height: 32rpx;
  771 +
  772 + &.row-spec {
  773 + height: 60rpx;
  774 + align-items: center;
  775 + }
  776 + }
  777 +
  778 + .row:last-child {
  779 + margin-bottom: 0;
  780 + }
  781 +
  782 + .label {
  783 + width: 200rpx;
  784 + margin-right: 14rpx;
  785 + color: rgba(0, 0, 0, 0.6);
  786 + font-size: 28rpx;
  787 + }
  788 +
  789 + .value {
  790 + flex: 1;
  791 + color: rgba(0, 0, 0, 0.9);
  792 + font-size: 28rpx;
  793 + white-space: pre-wrap;
  794 + word-break: break-all;
  795 + }
  796 +
  797 + .value-spec {
  798 + height: 60rpx;
  799 + display: flex;
  800 + align-items: center;
  801 + color: #000000;
  802 +
  803 + &_box {
  804 + position: relative;
  805 + width: 60rpx;
  806 + height: 60rpx;
  807 +
  808 + &_1 {
  809 + font-size: 16rpx;
  810 + position: absolute;
  811 + top: 0;
  812 + left: 0;
  813 + }
  814 +
  815 + &_2 {
  816 + font-size: 16rpx;
  817 + position: absolute;
  818 + bottom: 0;
  819 + left: 0;
  820 + }
  821 + }
  822 +
  823 + &_val {
  824 + font-size: 28rpx;
  825 +
  826 + &.p12 {
  827 + padding-right: 12rpx;
  828 + }
  829 + }
  830 + }
  831 +
  832 + .view-total {
  833 + padding-top: 20rpx;
  834 +
  835 + .head {
  836 + font-size: 32rpx;
  837 + font-weight: 600;
  838 + line-height: 50rpx;
  839 + color: rgba(0, 0, 0, 0.9);
  840 + padding-bottom: 16rpx;
  841 + margin-bottom: 24rpx;
  842 + border-bottom: 1px dashed #E7E7E7;
  843 + }
  844 +
  845 + .row {
  846 + display: flex;
  847 + margin-bottom: 24rpx;
  848 + line-height: 32rpx;
  849 +
  850 + .label {
  851 + width: 180rpx;
  852 + margin-right: 14rpx;
  853 + color: rgba(0, 0, 0, 0.6);
  854 + font-size: 28rpx;
  855 + }
  856 +
  857 + .value {
  858 + flex: 1;
  859 + color: rgba(0, 0, 0, 0.9);
  860 + font-size: 28rpx;
  861 + white-space: pre-wrap;
  862 + word-break: break-all;
  863 + }
  864 + }
  865 + }
  866 +}
  867 +</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.customerName }}</text>
  7 + <view class="row"><text class="label">订单编号</text><text class="value">{{ form.orderCode }}</text></view>
  8 + <view class="row"><text class="label">生产厂</text><text class="value">{{ form.workshopName }}</text></view>
  9 + </view>
  10 +
  11 + <!-- 产品 -->
  12 + <view class="section2">
  13 + <Product mode="view" :list="form.detailList" />
  14 + </view>
  15 +
  16 + <view class="title-header">
  17 + <image class="title-header_icon" src="/static/images/title.png" />
  18 + <span>本次试样概况</span>
  19 + </view>
  20 +
  21 + <view class="section">
  22 + <view class="row"><text class="label">表面</text><text class="value">{{ form.surface }}</text></view>
  23 + <view class="row"><text class="label">性能</text><text class="value">{{ form.performance }}</text></view>
  24 + <view class="row"><text class="label">公差</text><text class="value">{{ form.tolerance }}</text></view>
  25 + <view class="row"><text class="label">带型</text><text class="value">{{ form.bandingPattern }}</text></view>
  26 + <view class="row"><text class="label">包装</text><text class="value">{{ form.packaging }}</text></view>
  27 + <view class="row"><text class="label">件重条头</text><text class="value">{{ form.weight }}</text></view>
  28 + <view class="row"><text class="label">其他</text><text class="value">{{ form.other }}</text></view>
  29 + <view class="row"><text class="label">结论</text><text class="value">{{ getDicName('SAMPLE_RESULT',
  30 + form.sampleResult, dicOptions.SAMPLE_RESULT) }}</text></view>
  31 + <view class="row"><text class="label"></text><text class="value">{{ getDicName('SAMPLE_RESULT_SUB',
  32 + form.sampleResultSub, dicOptions.SAMPLE_RESULT_SUB) }}</text></view>
  33 + </view>
  34 + <view class="section">
  35 + <view class="row"><text class="label">客户评价依据</text><text class="value act"
  36 + @click="downloadFile(form.customerReviewsFileId, form.customerReviewsFileName)">{{
  37 + form.customerReviewsFileName
  38 + }}</text></view>
  39 + </view>
  40 + </view>
  41 + </scroll-view>
  42 + </view>
  43 +</template>
  44 +
  45 +<script>
  46 +import { getDetailApi } from '@/api/follow_up_form.js'
  47 +import Product from './product.vue'
  48 +import { downloadFile } from '@/utils/downloadFile.js'
  49 +import {
  50 + getDicByCodes
  51 +} from '@/utils/dic'
  52 +import {
  53 + getDicName
  54 +} from '@/utils/dic.js'
  55 +
  56 +export default {
  57 + name: 'FollowUpFormViewer',
  58 + components: { Product },
  59 + props: { id: { type: [String, Number], default: '' } },
  60 + data() {
  61 + return {
  62 + form: {},
  63 + dicOptions: {
  64 + SAMPLE_RESULT: [],
  65 + SAMPLE_RESULT_SUB: []
  66 + },
  67 + sampleResultLocal: [],
  68 + sampleResultSubLocal: []
  69 + }
  70 + },
  71 + computed: {
  72 + },
  73 + watch: {
  74 + id: {
  75 + immediate: true,
  76 + handler(val) {
  77 + this.loadAllDicData()
  78 + const v = (val !== undefined && val !== null) ? String(val) : ''
  79 + if (v) this.loadDetail(v)
  80 + }
  81 + }
  82 + },
  83 + onLoad(query) {
  84 + },
  85 + methods: {
  86 + async loadDetail(id) {
  87 + try {
  88 + const res = await getDetailApi(id)
  89 + this.form = res.data || {}
  90 + } catch (e) {
  91 + this.form = {}
  92 + }
  93 + },
  94 + downloadFile,
  95 + getDicName,
  96 + loadAllDicData() {
  97 + const dicCodes = ['SAMPLE_RESULT', 'SAMPLE_RESULT_SUB']
  98 + return getDicByCodes(dicCodes).then(results => {
  99 + this.dicOptions.SAMPLE_RESULT = results.SAMPLE_RESULT.data || []
  100 + this.dicOptions.SAMPLE_RESULT_SUB = results.SAMPLE_RESULT_SUB.data || []
  101 + this.sampleResultLocal = (this.dicOptions.SAMPLE_RESULT || []).map(it => ({
  102 + value: it.code,
  103 + text: it.name
  104 + }))
  105 + this.sampleResultSubLocal = (this.dicOptions.SAMPLE_RESULT_SUB || []).map(it => ({
  106 + value: it.code,
  107 + text: it.name
  108 + }))
  109 + }).catch(() => {
  110 + this.dicOptions = {
  111 + SAMPLE_RESULT: [],
  112 + SAMPLE_RESULT_SUB: []
  113 + }
  114 + this.sampleResultLocal = []
  115 + this.sampleResultSubLocal = []
  116 + })
  117 + },
  118 + getFormValues() {
  119 + delete this.form.status;
  120 + const m = this.form || {}
  121 + return JSON.parse(JSON.stringify(m))
  122 + },
  123 + }
  124 +}
  125 +</script>
  126 +
  127 +<style lang="scss" scoped>
  128 +.page {
  129 + display: flex;
  130 + flex-direction: column;
  131 + height: 100vh;
  132 +}
  133 +
  134 +.scroll {
  135 + flex: 1;
  136 + background: #f3f3f3;
  137 +}
  138 +
  139 +.detail-page {
  140 + padding-bottom: 144rpx;
  141 +}
  142 +
  143 +.section {
  144 + padding: 32rpx;
  145 + background: #fff;
  146 + margin-bottom: 20rpx;
  147 + position: relative;
  148 +
  149 +}
  150 +
  151 +.row {
  152 + display: flex;
  153 + margin-bottom: 28rpx;
  154 +
  155 + &:last-child {
  156 + margin-bottom: 0;
  157 + }
  158 +
  159 + &.company {
  160 + font-size: 36rpx;
  161 + font-weight: 600;
  162 + color: rgba(0, 0, 0, 0.9);
  163 + padding-top: 10rpx;
  164 + margin-bottom: 32rpx;
  165 + line-height: 50rpx;
  166 + }
  167 +
  168 + .label {
  169 + max-width: 400rpx;
  170 + margin-right: 20rpx;
  171 + line-height: 32rpx;
  172 + font-size: 28rpx;
  173 + color: rgba(0, 0, 0, 0.6);
  174 + }
  175 +
  176 + .value {
  177 + flex: 1;
  178 + line-height: 32rpx;
  179 + font-size: 28rpx;
  180 + color: rgba(0, 0, 0, 0.9);
  181 + text-align: right;
  182 + word-break: break-all;
  183 +
  184 + &.act {
  185 + color: $theme-primary;
  186 + }
  187 + }
  188 +}
  189 +
  190 +.title-header {
  191 + background-color: #fff;
  192 + display: flex;
  193 + align-items: center;
  194 + padding: 32rpx 32rpx 22rpx;
  195 + border-bottom: 1rpx dashed #f0f0f0;
  196 +
  197 + &_icon {
  198 + width: 32rpx;
  199 + height: 28rpx;
  200 + margin-right: 16rpx;
  201 + }
  202 +
  203 + span {
  204 + color: rgba(0, 0, 0, 0.9);
  205 + font-size: 32rpx;
  206 + line-height: 44rpx;
  207 + font-weight: 600;
  208 + }
  209 +}
  210 +</style>
@@ -38,7 +38,7 @@ @@ -38,7 +38,7 @@
38 <view class="grid-item" v-for="(g, idx) in it.items" :key="idx" v-if="!g.hidden" 38 <view class="grid-item" v-for="(g, idx) in it.items" :key="idx" v-if="!g.hidden"
39 @click="navigateTo(g.link)"> 39 @click="navigateTo(g.link)">
40 <image class="grid-icon" :src="g.icon" /> 40 <image class="grid-icon" :src="g.icon" />
41 - <text class="grid-text omit1">{{ g.text }}</text> 41 + <text class="grid-text omit2">{{ g.text }}</text>
42 </view> 42 </view>
43 </view> 43 </view>
44 </view> 44 </view>
@@ -190,6 +190,25 @@ export default { @@ -190,6 +190,25 @@ export default {
190 name: 'ReplenishmentOrder' 190 name: 'ReplenishmentOrder'
191 }] 191 }]
192 }, 192 },
  193 + {
  194 + title: '试样订单',
  195 + items: [{
  196 + text: '产品试样确认单',
  197 + icon: '/static/images/index/confirmation_form.png',
  198 + link: '/pages/confirmation_form/index',
  199 + name: 'ConfirmationForm'
  200 + },{
  201 + text: '产品试样结果反馈单',
  202 + icon: '/static/images/index/feedback_form.png',
  203 + link: '/pages/feedback_form/index',
  204 + name: 'FeedbackForm'
  205 + },{
  206 + text: '产品试样结果跟踪单',
  207 + icon: '/static/images/index/follow_up_form.png',
  208 + link: '/pages/follow_up_form/index',
  209 + name: 'FollowupForm'
  210 + }]
  211 + },
193 ], 212 ],
194 menuNames: [] 213 menuNames: []
195 } 214 }
@@ -64,6 +64,7 @@ export default { @@ -64,6 +64,7 @@ export default {
64 .label { 64 .label {
65 min-width: 120rpx; 65 min-width: 120rpx;
66 max-width: 420rpx; 66 max-width: 420rpx;
  67 + margin-right: 20rpx;
67 line-height: 32rpx; 68 line-height: 32rpx;
68 font-size: 28rpx; 69 font-size: 28rpx;
69 color: rgba(0, 0, 0, 0.6); 70 color: rgba(0, 0, 0, 0.6);
1 -<template>  
2 - <view class="help-container">  
3 - <view v-for="(item, findex) in list" :key="findex" :title="item.title" class="list-title">  
4 - <view class="text-title">  
5 - <view :class="item.icon"></view>{{ item.title }}  
6 - </view>  
7 - <view class="childList">  
8 - <view v-for="(child, zindex) in item.childList" :key="zindex" class="question" hover-class="hover"  
9 - @click="handleText(child)">  
10 - <view class="text-item">{{ child.title }}</view>  
11 - <view class="line" v-if="zindex !== item.childList.length - 1"></view>  
12 - </view>  
13 - </view>  
14 - </view>  
15 - </view>  
16 -</template>  
17 -  
18 -<script>  
19 - export default {  
20 - data() {  
21 - return {  
22 - list: [{  
23 - icon: 'iconfont icon-github',  
24 - title: 'erp移动版问题',  
25 - childList: [{  
26 - title: 'erp移动版开源吗?',  
27 - content: '框架开源,需要付费开放完整源代码'  
28 - }, {  
29 - title: 'erp移动版可以商用吗?',  
30 - content: '无商用限制'  
31 - }, {  
32 - title: 'erp移动版开源框架地址多少?',  
33 - content: 'https://gitee.com/i-love-ai/xy-mobile-master'  
34 - }]  
35 - },  
36 - {  
37 - icon: 'iconfont icon-help',  
38 - title: '其他问题',  
39 - childList: [{  
40 - title: '如何退出登录?',  
41 - content: '请点击[我的] - [应用设置] - [退出登录]即可退出登录',  
42 - }, {  
43 - title: '如何修改用户头像?',  
44 - content: '请点击[我的] - [选择头像] - [点击提交]即可更换用户头像',  
45 - }, {  
46 - title: '如何修改登录密码?',  
47 - content: '请点击[我的] - [应用设置] - [修改密码]即可修改登录密码',  
48 - }]  
49 - }  
50 - ]  
51 - }  
52 - },  
53 - methods: {  
54 - handleText(item) {  
55 - this.$tab.navigateTo(`/pages/common/textview/index?title=${item.title}&content=${item.content}`)  
56 - }  
57 - }  
58 - }  
59 -</script>  
60 -  
61 -<style lang="scss" scoped>  
62 - page {  
63 - background-color: #f8f8f8;  
64 - }  
65 -  
66 - .help-container {  
67 - margin-bottom: 100rpx;  
68 - padding: 30rpx;  
69 - }  
70 -  
71 - .list-title {  
72 - margin-bottom: 30rpx;  
73 - }  
74 -  
75 - .childList {  
76 - background: #ffffff;  
77 - box-shadow: 0px 0px 10rpx rgba(193, 193, 193, 0.2);  
78 - border-radius: 16rpx;  
79 - margin-top: 10rpx;  
80 - }  
81 -  
82 - .line {  
83 - width: 100%;  
84 - height: 1rpx;  
85 - background-color: #F5F5F5;  
86 - }  
87 -  
88 - .text-title {  
89 - color: #303133;  
90 - font-size: 32rpx;  
91 - font-weight: bold;  
92 - margin-left: 10rpx;  
93 -  
94 - .iconfont {  
95 - font-size: 16px;  
96 - margin-right: 10rpx;  
97 - }  
98 - }  
99 -  
100 - .text-item {  
101 - font-size: 28rpx;  
102 - padding: 24rpx;  
103 - }  
104 -  
105 - .question {  
106 - color: #606266;  
107 - font-size: 28rpx;  
108 - }  
109 -</style>  
1 -<template>  
2 - <view class="mine-container" :style="{height: `${windowHeight}px`}">  
3 - <!--顶部个人信息栏-->  
4 - <view class="header-section">  
5 - <view class="flex padding justify-between">  
6 - <view class="flex align-center">  
7 - <view v-if="!avatar" class="cu-avatar xl round bg-white">  
8 - <view class="iconfont icon-people text-gray icon"></view>  
9 - </view>  
10 - <image v-if="avatar" @click="handleToAvatar" :src="avatar" class="cu-avatar xl round" mode="widthFix">  
11 - </image>  
12 - <view v-if="!name" @click="handleToLogin" class="login-tip">  
13 - 点击登录  
14 - </view>  
15 - <view v-if="name" @click="handleToInfo" class="user-info">  
16 - <view class="u_title">  
17 - {{ name }}  
18 - </view>  
19 - <view @click="handleToInfo" class="flex align-center">  
20 - <text>个人信息</text>  
21 - <view class="iconfont icon-right"></view>  
22 - </view>  
23 - </view>  
24 - </view>  
25 -  
26 - </view>  
27 - </view>  
28 -  
29 - <view class="content-section">  
30 - <view class="mine-actions grid col-4 text-center">  
31 - <view class="action-item" @click="handleJiaoLiuQun">  
32 - <view class="iconfont icon-friendfill text-pink icon"></view>  
33 - <text class="text">交流群</text>  
34 - </view>  
35 - <view class="action-item" @click="handleBuilding">  
36 - <view class="iconfont icon-service text-blue icon"></view>  
37 - <text class="text">在线客服</text>  
38 - </view>  
39 - <view class="action-item" @click="handleJiaoLiuQun">  
40 - <view class="iconfont icon-community text-mauve icon"></view>  
41 - <text class="text">反馈社区</text>  
42 - </view>  
43 - <view class="action-item" @click="handleLink">  
44 - <view class="iconfont icon-dianzan text-green icon"></view>  
45 - <text class="text">点赞我们</text>  
46 - </view>  
47 - </view>  
48 -  
49 - <view class="menu-list">  
50 - <view class="list-cell list-cell-arrow" @click="handleToEditInfo">  
51 - <view class="menu-item-box">  
52 - <view class="iconfont icon-user menu-icon"></view>  
53 - <view>编辑资料</view>  
54 - </view>  
55 - </view>  
56 - <view class="list-cell list-cell-arrow" @click="handleHelp">  
57 - <view class="menu-item-box">  
58 - <view class="iconfont icon-help menu-icon"></view>  
59 - <view>常见问题</view>  
60 - </view>  
61 - </view>  
62 - <view class="list-cell list-cell-arrow" @click="handleAbout">  
63 - <view class="menu-item-box">  
64 - <view class="iconfont icon-aixin menu-icon"></view>  
65 - <view>关于我们</view>  
66 - </view>  
67 - </view>  
68 - <view class="list-cell list-cell-arrow" @click="handleToSetting">  
69 - <view class="menu-item-box">  
70 - <view class="iconfont icon-setting menu-icon"></view>  
71 - <view>应用设置</view>  
72 - </view>  
73 - </view>  
74 - </view>  
75 -  
76 - </view>  
77 - <view>  
78 - <uni-popup ref="alertDialog" type="dialog">  
79 - <uni-popup-dialog type="info" cancelText="关闭" confirmText="确定" title="公众号" content="公众号">  
80 - <view><image src="../../static/images/gzh.jpg" style="width: 250px;height: 250px;"></image></view>  
81 - </uni-popup-dialog>  
82 - </uni-popup>  
83 - </view>  
84 - </view>  
85 -</template>  
86 -  
87 -<script>  
88 - import storage from '@/utils/storage'  
89 -  
90 - export default {  
91 - data() {  
92 - return {  
93 - globalConfig: getApp().globalData.config,  
94 - name: this.$store.state.user.name,  
95 - version: getApp().globalData.config.appInfo.version  
96 - }  
97 - },  
98 -  
99 - computed: {  
100 -  
101 - avatar() {  
102 - return this.$store.state.user.avatar  
103 - },  
104 - windowHeight() {  
105 - return uni.getSystemInfoSync().windowHeight - 50  
106 - }  
107 - },  
108 - methods: {  
109 -  
110 -  
111 - handleToInfo() {  
112 - this.$tab.navigateTo('/pages/mine/info/index')  
113 - },  
114 - handleToEditInfo() {  
115 - this.$tab.navigateTo('/pages/mine/info/edit')  
116 - },  
117 - handleToSetting() {  
118 - this.$tab.navigateTo('/pages/mine/setting/index')  
119 - },  
120 - handleToLogin() {  
121 - this.$tab.reLaunch('/pages/login')  
122 - },  
123 - handleToAvatar() {  
124 - this.$tab.navigateTo('/pages/mine/avatar/index')  
125 - },  
126 - handleLogout() {  
127 - this.$modal.confirm('确定注销并退出系统吗?').then(() => {  
128 - this.$store.dispatch('LogOut').then(() => {  
129 - this.$tab.reLaunch('/pages/index')  
130 - })  
131 - })  
132 - },  
133 - handleHelp() {  
134 - this.$tab.navigateTo('/pages/mine/help/index')  
135 -  
136 - },  
137 - handleAbout() {  
138 - this.$tab.navigateTo('/pages/mine/about/index')  
139 - },  
140 - handleJiaoLiuQun() {  
141 - this.$refs.alertDialog.open('center');  
142 - },  
143 - handleBuilding() {  
144 - this.$modal.showToast('添加CDERP客服 QQ:3783722918')  
145 - },  
146 - handleLink() {  
147 - // let site = this.globalConfig.appInfo.agreements[2]  
148 - // this.$tab.navigateTo('/pages/common/webview/index?title='+site.title+'&url='+site.url)  
149 - this.$refs.alertDialog.open('center');  
150 - }  
151 -  
152 - }  
153 - }  
154 -</script>  
155 -  
156 -<style lang="scss">  
157 - page {  
158 - background-color: #f5f6f7;  
159 - }  
160 -  
161 - .mine-container {  
162 - width: 100%;  
163 - height: 100%;  
164 -  
165 -  
166 - .header-section {  
167 - padding: 15px 15px 45px 15px;  
168 - background-color: #3c96f3;  
169 - color: white;  
170 -  
171 - .login-tip {  
172 - font-size: 18px;  
173 - margin-left: 10px;  
174 - }  
175 -  
176 - .cu-avatar {  
177 - border: 2px solid #eaeaea;  
178 -  
179 - .icon {  
180 - font-size: 40px;  
181 - }  
182 - }  
183 -  
184 - .user-info {  
185 - margin-left: 15px;  
186 -  
187 - .u_title {  
188 - font-size: 14px;  
189 - line-height: 30px;  
190 - }  
191 - }  
192 - }  
193 -  
194 - .content-section {  
195 - position: relative;  
196 - top: -50px;  
197 -  
198 - .mine-actions {  
199 - margin: 15px 15px;  
200 - padding: 20px 0px;  
201 - border-radius: 8px;  
202 - background-color: white;  
203 -  
204 - .action-item {  
205 - .icon {  
206 - font-size: 28px;  
207 - }  
208 -  
209 - .text {  
210 - display: block;  
211 - font-size: 13px;  
212 - margin: 8px 0px;  
213 - }  
214 - }  
215 - }  
216 - }  
217 - }  
218 -</style>  
@@ -55,11 +55,16 @@ @@ -55,11 +55,16 @@
55 <view class="readonly-text">{{ form.deliveryMethod }}</view> 55 <view class="readonly-text">{{ form.deliveryMethod }}</view>
56 </template> 56 </template>
57 </uni-list-item> 57 </uni-list-item>
  58 + <uni-list-item title="是否为试样订单">
  59 + <template v-slot:footer>
  60 + <view class="readonly-text">{{ form.sampleOrder ? '是' : '否' }}</view>
  61 + </template>
  62 + </uni-list-item>
58 </view> 63 </view>
59 64
60 <!-- 产品 --> 65 <!-- 产品 -->
61 <view class="section2"> 66 <view class="section2">
62 - <Product mode="add" :list="initPurchaseOrderLineList" @change="purchaseOrderLineListChange" 67 + <Product mode="approve" :list="initPurchaseOrderLineList" @change="purchaseOrderLineListChange"
63 :orderDate="form.orderDate" /> 68 :orderDate="form.orderDate" />
64 </view> 69 </view>
65 70
@@ -69,9 +74,9 @@ @@ -69,9 +74,9 @@
69 <uni-easyinput v-model="form.priceListNo" placeholder="请输入价格表编号" :inputBorder="false" /> 74 <uni-easyinput v-model="form.priceListNo" placeholder="请输入价格表编号" :inputBorder="false" />
70 </template> 75 </template>
71 </uni-list-item> 76 </uni-list-item>
72 - <uni-list-item title="开票情况"> 77 + <uni-list-item title="开票要求">
73 <template v-slot:footer> 78 <template v-slot:footer>
74 - <uni-easyinput v-model="form.invoicingStatus" placeholder="请输入开票情况" :inputBorder="false" /> 79 + <uni-easyinput v-model="form.invoicingStatus" placeholder="请输入开票要求" :inputBorder="false" />
75 </template> 80 </template>
76 </uni-list-item> 81 </uni-list-item>
77 <uni-list-item class="amount-item"> 82 <uni-list-item class="amount-item">
@@ -170,20 +175,23 @@ @@ -170,20 +175,23 @@
170 <view class="row"><text class="label">生产厂</text><text class="value">{{ form.workshopName }}</text></view> 175 <view class="row"><text class="label">生产厂</text><text class="value">{{ form.workshopName }}</text></view>
171 <view class="row"><text class="label">办事处</text><text class="value">{{ form.deptName }}</text></view> 176 <view class="row"><text class="label">办事处</text><text class="value">{{ form.deptName }}</text></view>
172 <view class="row"><text class="label">区域</text><text class="value">{{ form.regionName }}</text></view> 177 <view class="row"><text class="label">区域</text><text class="value">{{ form.regionName }}</text></view>
173 - <view class="row"><text class="label">备货单位/人(生产标准)</text><text class="value">{{ form.stockUpCompanyName }}</text></view> 178 + <view class="row"><text class="label">备货单位/人(生产标准)</text><text class="value">{{ form.stockUpCompanyName
  179 + }}</text></view>
174 <view class="row"><text class="label">结算方式或期限</text><text class="value">{{ form.settlementTerms }}</text> 180 <view class="row"><text class="label">结算方式或期限</text><text class="value">{{ form.settlementTerms }}</text>
175 </view> 181 </view>
176 <view class="row"><text class="label">交货方式</text><text class="value">{{ form.deliveryMethod }}</text></view> 182 <view class="row"><text class="label">交货方式</text><text class="value">{{ form.deliveryMethod }}</text></view>
  183 + <view class="row"><text class="label">是否为试样订单</text><text class="value">{{ form.sampleOrder ? '是' : '否'
  184 + }}</text></view>
177 </view> 185 </view>
178 - 186 + <!--是否试样订单可编辑 特例-->
179 <!-- 产品 --> 187 <!-- 产品 -->
180 <view class="mgb10"> 188 <view class="mgb10">
181 - <Product mode="view" :list="form.purchaseOrderLineList" :totalQuantity="form.totalQuantity || 0" /> 189 + <Product mode="approve2" :list="initPurchaseOrderLineList" @change="purchaseOrderLineListChange" />
182 </view> 190 </view>
183 191
184 <view class="section"> 192 <view class="section">
185 <view class="row"><text class="label">价格表编号</text><text class="value">{{ form.priceListNo }}</text></view> 193 <view class="row"><text class="label">价格表编号</text><text class="value">{{ form.priceListNo }}</text></view>
186 - <view class="row"><text class="label">开票情况</text><text class="value">{{ form.invoicingStatus }}</text></view> 194 + <view class="row"><text class="label">开票要求</text><text class="value">{{ form.invoicingStatus }}</text></view>
187 <view class="row"><text class="label">运费</text><text class="value">{{ form.shippingCost }}</text></view> 195 <view class="row"><text class="label">运费</text><text class="value">{{ form.shippingCost }}</text></view>
188 <view class="row"><text class="label">执行标准</text><text class="value">{{ getDicName('APPLICABLE_STANDARD', 196 <view class="row"><text class="label">执行标准</text><text class="value">{{ getDicName('APPLICABLE_STANDARD',
189 form.executionStandard, dicOptions.APPLICABLE_STANDARD) }}</text></view> 197 form.executionStandard, dicOptions.APPLICABLE_STANDARD) }}</text></view>
@@ -207,7 +215,7 @@ @@ -207,7 +215,7 @@
207 <view class="row"><text class="label">备注</text><text class="value">{{ form.remarks }}</text></view> 215 <view class="row"><text class="label">备注</text><text class="value">{{ form.remarks }}</text></view>
208 </view> 216 </view>
209 <!-- 品质科 可填写(不是办事处内勤) --> 217 <!-- 品质科 可填写(不是办事处内勤) -->
210 - <uni-list v-if="form.showProductionProcess" > 218 + <uni-list v-if="form.showProductionProcess">
211 <uni-list-item title="生产工艺"> 219 <uni-list-item title="生产工艺">
212 <template v-slot:footer> 220 <template v-slot:footer>
213 <uni-easyinput type="textarea" v-model="form.productionProcess" placeholder="请输入生产工艺" 221 <uni-easyinput type="textarea" v-model="form.productionProcess" placeholder="请输入生产工艺"
@@ -217,7 +225,14 @@ @@ -217,7 +225,14 @@
217 </uni-list> 225 </uni-list>
218 </view> 226 </view>
219 </scroll-view> 227 </scroll-view>
220 - 228 + <view class="footer">
  229 + <view class="view-total">
  230 + <view class="head">合计</view>
  231 + <view class="row">
  232 + <text class="label">总数量</text><text class="value">{{ form.totalQuantity }}</text>
  233 + </view>
  234 + </view>
  235 + </view>
221 </view> 236 </view>
222 </template> 237 </template>
223 238
@@ -316,7 +331,7 @@ export default { @@ -316,7 +331,7 @@ export default {
316 const m = res.data || {} 331 const m = res.data || {}
317 const next = { ...this.form, ...m } 332 const next = { ...this.form, ...m }
318 next.id = m.id || m.code || id 333 next.id = m.id || m.code || id
319 - next.purchaseOrderLineList = Array.isArray(m.purchaseOrderLineList) ? m.purchaseOrderLineList.map(x => ({ 334 + next.purchaseOrderLineList = Array.isArray(m.purchaseOrderLineList) ? m.purchaseOrderLineList.map(x => ({
320 ...x, 335 ...x,
321 assessmentExceedsAgreement: Number(x.assessmentExceedsAgreement || 0).toFixed(2) || 0.00, 336 assessmentExceedsAgreement: Number(x.assessmentExceedsAgreement || 0).toFixed(2) || 0.00,
322 })) : [] 337 })) : []
@@ -616,7 +631,7 @@ export default { @@ -616,7 +631,7 @@ export default {
616 631
617 .view-page { 632 .view-page {
618 .scroll { 633 .scroll {
619 - padding: 0; 634 + padding: 0 0 180rpx;
620 } 635 }
621 636
622 .section { 637 .section {
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
12 {{ getDicName('AUDIT_STATUS',form.examineStatus, dicOptions.AUDIT_STATUS) }} 12 {{ getDicName('AUDIT_STATUS',form.examineStatus, dicOptions.AUDIT_STATUS) }}
13 </text> 13 </text>
14 </text> 14 </text>
15 - 15 +
16 </view> 16 </view>
17 <view class="row"><text class="label">供货单位</text><text class="value">{{ getDicName('SUPPLIER', 17 <view class="row"><text class="label">供货单位</text><text class="value">{{ getDicName('SUPPLIER',
18 form.supplyUnit, dicOptions.SUPPLIER) }}</text></view> 18 form.supplyUnit, dicOptions.SUPPLIER) }}</text></view>
@@ -27,6 +27,7 @@ @@ -27,6 +27,7 @@
27 </view> 27 </view>
28 <view class="row"><text class="label">交货方式</text><text class="value">{{ form.deliveryMethod }}</text></view> 28 <view class="row"><text class="label">交货方式</text><text class="value">{{ form.deliveryMethod }}</text></view>
29 <view class="row"><text class="label">是否冻结</text><text class="value">{{ form.freeze ? '是' : '否' }}</text></view> 29 <view class="row"><text class="label">是否冻结</text><text class="value">{{ form.freeze ? '是' : '否' }}</text></view>
  30 + <view class="row"><text class="label">是否为试样订单</text><text class="value">{{ form.sampleOrder ? '是' : '否' }}</text></view>
30 </view> 31 </view>
31 32
32 <!-- 产品 --> 33 <!-- 产品 -->
@@ -36,7 +37,7 @@ @@ -36,7 +37,7 @@
36 37
37 <view class="section"> 38 <view class="section">
38 <view class="row"><text class="label">价格表编号</text><text class="value">{{ form.priceListNo }}</text></view> 39 <view class="row"><text class="label">价格表编号</text><text class="value">{{ form.priceListNo }}</text></view>
39 - <view class="row"><text class="label">开票情况</text><text class="value">{{ form.invoicingStatus }}</text></view> 40 + <view class="row"><text class="label">开票要求</text><text class="value">{{ form.invoicingStatus }}</text></view>
40 <view class="row"><text class="label">运费</text><text class="value">{{ form.shippingCost }}</text></view> 41 <view class="row"><text class="label">运费</text><text class="value">{{ form.shippingCost }}</text></view>
41 <view class="row"><text class="label">执行标准</text><text class="value">{{ getDicName('APPLICABLE_STANDARD', 42 <view class="row"><text class="label">执行标准</text><text class="value">{{ getDicName('APPLICABLE_STANDARD',
42 form.executionStandard, dicOptions.APPLICABLE_STANDARD) }}</text></view> 43 form.executionStandard, dicOptions.APPLICABLE_STANDARD) }}</text></view>
@@ -107,8 +108,9 @@ export default { @@ -107,8 +108,9 @@ export default {
107 return { 108 return {
108 isRefuse: e === 'REFUSE', 109 isRefuse: e === 'REFUSE',
109 isAudit: e === 'AUDIT', 110 isAudit: e === 'AUDIT',
  111 + isAuditDetail: !this.form.sampleOrder,
110 canExamine: d, 112 canExamine: d,
111 - canDeliveryApply: s === 'ISSUED' && (!this.form.freeze || false), 113 + canDeliveryApply: s === 'ISSUED' && (!this.form.freeze || false) && Number(this.form.totalQuantity) > 0,
112 contractCreateBy: this.form.contractCreateBy 114 contractCreateBy: this.form.contractCreateBy
113 } 115 }
114 }, 116 },
@@ -117,7 +119,7 @@ export default { @@ -117,7 +119,7 @@ export default {
117 console.log('displayButtons__f', f) 119 console.log('displayButtons__f', f)
118 return [ 120 return [
119 { ...this.buttons[0], visible: f.isRefuse && f.contractCreateBy && this.$auth.hasPermi('order-manage:order-list:modify') }, 121 { ...this.buttons[0], visible: f.isRefuse && f.contractCreateBy && this.$auth.hasPermi('order-manage:order-list:modify') },
120 - { ...this.buttons[1], visible: this.$auth.hasPermi('order-manage:order-list:review') }, 122 + { ...this.buttons[1], visible: f.isAuditDetail && this.$auth.hasPermi('order-manage:order-list:review') },
121 { ...this.buttons[2], visible: f.isAudit && f.canExamine && this.$auth.hasPermi('order-manage:order-list:approve') }, 123 { ...this.buttons[2], visible: f.isAudit && f.canExamine && this.$auth.hasPermi('order-manage:order-list:approve') },
122 { ...this.buttons[3], visible: f.canDeliveryApply && this.$auth.hasPermi('order-manage:order-list:apply') }, 124 { ...this.buttons[3], visible: f.canDeliveryApply && this.$auth.hasPermi('order-manage:order-list:apply') },
123 { ...this.buttons[4], visible: f.isRefuse && f.contractCreateBy && this.$auth.hasPermi('order-manage:order-list:cancel') }, 125 { ...this.buttons[4], visible: f.isRefuse && f.contractCreateBy && this.$auth.hasPermi('order-manage:order-list:cancel') },
@@ -312,6 +314,7 @@ export default { @@ -312,6 +314,7 @@ export default {
312 314
313 .label { 315 .label {
314 max-width: 420rpx; 316 max-width: 420rpx;
  317 + margin-right: 20rpx;
315 line-height: 32rpx; 318 line-height: 32rpx;
316 font-size: 28rpx; 319 font-size: 28rpx;
317 color: rgba(0, 0, 0, 0.6); 320 color: rgba(0, 0, 0, 0.6);
@@ -31,6 +31,7 @@ @@ -31,6 +31,7 @@
31 <view class="info-row"><text>生产厂</text><text>{{ item.workshopName }}</text></view> 31 <view class="info-row"><text>生产厂</text><text>{{ item.workshopName }}</text></view>
32 <view class="info-row"><text>办事处</text><text>{{ item.deptName }}</text></view> 32 <view class="info-row"><text>办事处</text><text>{{ item.deptName }}</text></view>
33 <view class="info-row"><text>订货日期</text><text>{{ item.orderDate }}</text></view> 33 <view class="info-row"><text>订货日期</text><text>{{ item.orderDate }}</text></view>
  34 + <view class="info-row"><text>是否为试样订单</text><text>{{ item.sampleOrder ? '是' : '否' }}</text></view>
34 </view> 35 </view>
35 </template> 36 </template>
36 </CardList> 37 </CardList>
@@ -65,6 +66,12 @@ @@ -65,6 +66,12 @@
65 </view> 66 </view>
66 67
67 <view class="form-item"> 68 <view class="form-item">
  69 + <view class="label">是否为试样订单</view>
  70 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  71 + v-model="model.sampleOrder" @change="onSampleOrderChange" :localdata="sampleOrderOptions" />
  72 + </view>
  73 +
  74 + <view class="form-item">
68 <view class="label">订货日期</view> 75 <view class="label">订货日期</view>
69 <uni-datetime-picker type="daterange" v-model="model.dateRange" start="2023-01-01" @change="onDateChange($event, model)" /> 76 <uni-datetime-picker type="daterange" v-model="model.dateRange" start="2023-01-01" @change="onDateChange($event, model)" />
70 </view> 77 </view>
@@ -103,6 +110,7 @@ export default { @@ -103,6 +110,7 @@ export default {
103 workshopOptions: [], 110 workshopOptions: [],
104 statusOptions: [], 111 statusOptions: [],
105 examineStatusOptions: [], 112 examineStatusOptions: [],
  113 + sampleOrderOptions: [{ text: '是', value: 'true' }, { text: '否', value: 'false' }],
106 query: {}, 114 query: {},
107 extraParams: {}, 115 extraParams: {},
108 currentItems: [] 116 currentItems: []
@@ -202,6 +210,11 @@ export default { @@ -202,6 +210,11 @@ export default {
202 const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ? e.value : '') 210 const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ? e.value : '')
203 this.filterForm.examineStatus = raw 211 this.filterForm.examineStatus = raw
204 }, 212 },
  213 + onSampleOrderChange(e) {
  214 + const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ? e.value : '')
  215 + console.log('onSampleOrderChange', raw, typeof raw)
  216 + this.filterForm.sampleOrder = raw;
  217 + },
205 onWorkshopChange(e) { 218 onWorkshopChange(e) {
206 const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ? e.value : '') 219 const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ? e.value : '')
207 this.filterForm.workshopId = raw 220 this.filterForm.workshopId = raw
@@ -54,6 +54,11 @@ @@ -54,6 +54,11 @@
54 <view class="readonly-text">{{ form.deliveryMethod }}</view> 54 <view class="readonly-text">{{ form.deliveryMethod }}</view>
55 </template> 55 </template>
56 </uni-list-item> 56 </uni-list-item>
  57 + <uni-list-item title="是否为试样订单">
  58 + <template v-slot:footer>
  59 + <view class="readonly-text">{{ form.sampleOrder ? '是' : '否' }}</view>
  60 + </template>
  61 + </uni-list-item>
57 </view> 62 </view>
58 63
59 <!-- 产品 --> 64 <!-- 产品 -->
@@ -67,9 +72,9 @@ @@ -67,9 +72,9 @@
67 <uni-easyinput v-model="form.priceListNo" placeholder="请输入价格表编号" :inputBorder="false" /> 72 <uni-easyinput v-model="form.priceListNo" placeholder="请输入价格表编号" :inputBorder="false" />
68 </template> 73 </template>
69 </uni-list-item> 74 </uni-list-item>
70 - <uni-list-item title="开票情况"> 75 + <uni-list-item title="开票要求">
71 <template v-slot:footer> 76 <template v-slot:footer>
72 - <uni-easyinput v-model="form.invoicingStatus" placeholder="请输入开票情况" :inputBorder="false" /> 77 + <uni-easyinput v-model="form.invoicingStatus" placeholder="请输入开票要求" :inputBorder="false" />
73 </template> 78 </template>
74 </uni-list-item> 79 </uni-list-item>
75 <uni-list-item class="amount-item"> 80 <uni-list-item class="amount-item">
@@ -150,7 +155,7 @@ @@ -150,7 +155,7 @@
150 155
151 </uni-list> 156 </uni-list>
152 </scroll-view> 157 </scroll-view>
153 - 158 +
154 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" 159 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
155 @confirm="onSheetConfirm" /> 160 @confirm="onSheetConfirm" />
156 </view> 161 </view>
@@ -225,7 +230,7 @@ export default { @@ -225,7 +230,7 @@ export default {
225 const m = res.data || {} 230 const m = res.data || {}
226 const next = { ...this.form, ...m } 231 const next = { ...this.form, ...m }
227 next.id = m.id || m.code || id 232 next.id = m.id || m.code || id
228 - next.purchaseOrderLineList = Array.isArray(m.purchaseOrderLineList) ? m.purchaseOrderLineList.map(x => ({ 233 + next.purchaseOrderLineList = Array.isArray(m.purchaseOrderLineList) ? m.purchaseOrderLineList.map(x => ({
229 ...x, 234 ...x,
230 assessmentExceedsAgreement: Number(x.assessmentExceedsAgreement || 0).toFixed(2) || 0.00, 235 assessmentExceedsAgreement: Number(x.assessmentExceedsAgreement || 0).toFixed(2) || 0.00,
231 })) : [] 236 })) : []
@@ -94,6 +94,152 @@ @@ -94,6 +94,152 @@
94 </view> 94 </view>
95 </view> 95 </view>
96 96
  97 + <view v-else-if="mode === 'approve'" class="section">
  98 + <view v-for="(item, idx) in items" :key="'a-' + idx" class="block">
  99 + <view class="row"><text class="label">行业</text><text class="value">{{ item.industry }}</text></view>
  100 + <view class="row"><text class="label">品质</text><text class="value">{{ item.quality }}</text></view>
  101 + <view class="row"><text class="label">牌号</text><text class="value">{{ item.brand }}</text></view>
  102 +
  103 + <view v-show="!item.collapsed">
  104 + <!-- 厚(公差) * 宽(公差) * 长(公差) -->
  105 + <view class="row row-spec"><text class="label">规格(mm)</text>
  106 + <view class="value value-spec">
  107 + <view v-if="item.thickness" class="value-spec_val">{{ item.thickness }}</view>
  108 + <view v-if="item.thickness" class="value-spec_box">
  109 + <view v-if="item.thicknessTolPos" class="value-spec_box_1">+{{ item.thicknessTolPos }}
  110 + </view>
  111 + <view v-if="item.thicknessTolNeg" class="value-spec_box_2">-{{ item.thicknessTolNeg }}
  112 + </view>
  113 + </view>
  114 + <view v-if="item.width" class="value-spec_val p12">*</view>
  115 + <view v-if="item.width" class="value-spec_val">{{ item.width }}</view>
  116 + <view v-if="item.width" class="value-spec_box">
  117 + <view v-if="item.widthTolPos" class="value-spec_box_1">{{ item.widthTolPos > 0 ? '+' + item.widthTolPos : item.widthTolPos }}</view>
  118 + <view v-if="item.widthTolNeg" class="value-spec_box_2">{{ item.widthTolNeg > 0 ? '+' + item.widthTolNeg : item.widthTolNeg }}</view>
  119 + </view>
  120 + <view v-if="item.length" class="value-spec_val p12">*</view>
  121 + <view v-if="item.length" class="value-spec_val">{{ item.length }}</view>
  122 + <view v-if="item.length" class="value-spec_box">
  123 + <view v-if="item.lengthTolPos" class="value-spec_box_1">{{ item.lengthTolPos > 0 ? '+' + item.lengthTolPos : item.lengthTolPos }}</view>
  124 + <view v-if="item.lengthTolNeg" class="value-spec_box_2">{{ item.lengthTolNeg > 0 ? '+' + item.lengthTolNeg : item.lengthTolNeg }}</view>
  125 + </view>
  126 + </view>
  127 + </view>
  128 + <view class="row"><text class="label">状态</text><text class="value">{{ item.status }}</text></view>
  129 + <view class="row" :class="{ 'noneStyle': !item.showSalesPrice }"><text
  130 + class="label">数量kg</text><text class="value">{{ item.quantity }}</text>
  131 + </view>
  132 + <view class="row" :class="{ 'noneStyle': item.showSalesPrice }" v-if="item.showSalesPrice"><text
  133 + class="label">销售价格</text><text class="value">{{
  134 + item.salesPrice }}</text></view>
  135 + <uni-list class="edit-list">
  136 + <uni-list-item class="amount-item">
  137 + <template v-slot:body>
  138 + <view class="item-title"><text>包装费</text></view>
  139 + </template>
  140 + <template v-slot:footer>
  141 + <view class="amount-row">
  142 + <uni-easyinput type="digit" v-model="item.packagingFee" placeholder="0.00"
  143 + :inputBorder="false"
  144 + @input="onNonNegativeNumberInput($event, item, idx, 'packagingFee')"
  145 + @blur="onNonNegativeNumberBlur(item, idx, 'packagingFee')" />
  146 + <text class="unit">元</text>
  147 + </view>
  148 + </template>
  149 + </uni-list-item>
  150 + <uni-list-item title="发货日期">
  151 + <template v-slot:footer>
  152 + <uni-datetime-picker type="date" v-model="item.deliveryDate" :start="minDeliveryDate"
  153 + @change="onDeliveryChange($event, item, idx)" />
  154 + </template>
  155 + </uni-list-item>
  156 + <uni-list-item title="考核超协">
  157 + <template v-slot:footer>
  158 + <uni-easyinput :disabled="pageType === 'modify'"
  159 + v-model="item.assessmentExceedsAgreement"
  160 + :placeholder="pageType === 'modify' ? '' : '请输入考核超协'" :inputBorder="false" />
  161 + </template>
  162 + </uni-list-item>
  163 + <uni-list-item class="select-item" :class="String(item.sampleOrder) ? 'is-filled' : 'is-empty'" clickable
  164 + @click="openSheet(idx)" :rightText="(item.sampleOrder ? '是' : '否') || '请选择'" showArrow>
  165 + <template v-slot:body>
  166 + <view class="item-title"><text>是否为试样订单</text></view>
  167 + </template>
  168 + </uni-list-item>
  169 + </uni-list>
  170 + </view>
  171 +
  172 + <view class="block-ops">
  173 + <div class="toggle" @click="toggleItem(idx)">
  174 + <image :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'"
  175 + class="icon" />
  176 + {{ item.collapsed ? '展开' : '收起' }}
  177 + </div>
  178 + </view>
  179 + </view>
  180 + </view>
  181 +
  182 + <view v-else-if="mode === 'approve2'" class="section">
  183 + <view v-for="(item, idx) in items" :key="'a-' + idx" class="block">
  184 + <view class="row"><text class="label">行业</text><text class="value">{{ item.industry }}</text></view>
  185 + <view class="row"><text class="label">品质</text><text class="value">{{ item.quality }}</text></view>
  186 + <view class="row"><text class="label">牌号</text><text class="value">{{ item.brand }}</text></view>
  187 +
  188 + <view v-show="!item.collapsed">
  189 + <!-- 厚(公差) * 宽(公差) * 长(公差) -->
  190 + <view class="row row-spec"><text class="label">规格(mm)</text>
  191 + <view class="value value-spec">
  192 + <view v-if="item.thickness" class="value-spec_val">{{ item.thickness }}</view>
  193 + <view v-if="item.thickness" class="value-spec_box">
  194 + <view v-if="item.thicknessTolPos" class="value-spec_box_1">+{{ item.thicknessTolPos }}
  195 + </view>
  196 + <view v-if="item.thicknessTolNeg" class="value-spec_box_2">-{{ item.thicknessTolNeg }}
  197 + </view>
  198 + </view>
  199 + <view v-if="item.width" class="value-spec_val p12">*</view>
  200 + <view v-if="item.width" class="value-spec_val">{{ item.width }}</view>
  201 + <view v-if="item.width" class="value-spec_box">
  202 + <view v-if="item.widthTolPos" class="value-spec_box_1">{{ item.widthTolPos > 0 ? '+' + item.widthTolPos : item.widthTolPos }}</view>
  203 + <view v-if="item.widthTolNeg" class="value-spec_box_2">{{ item.widthTolNeg > 0 ? '+' + item.widthTolNeg : item.widthTolNeg }}</view>
  204 + </view>
  205 + <view v-if="item.length" class="value-spec_val p12">*</view>
  206 + <view v-if="item.length" class="value-spec_val">{{ item.length }}</view>
  207 + <view v-if="item.length" class="value-spec_box">
  208 + <view v-if="item.lengthTolPos" class="value-spec_box_1">{{ item.lengthTolPos > 0 ? '+' + item.lengthTolPos : item.lengthTolPos }}</view>
  209 + <view v-if="item.lengthTolNeg" class="value-spec_box_2">{{ item.lengthTolNeg > 0 ? '+' + item.lengthTolNeg : item.lengthTolNeg }}</view>
  210 + </view>
  211 + </view>
  212 + </view>
  213 + <view class="row"><text class="label">状态</text><text class="value">{{ item.status }}</text></view>
  214 + <view class="row" :class="{ 'noneStyle': !item.showSalesPrice }"><text
  215 + class="label">数量kg</text><text class="value">{{ item.quantity }}</text>
  216 + </view>
  217 + <view class="row" v-if="item.showSalesPrice"><text
  218 + class="label">销售价格</text><text class="value">{{
  219 + item.salesPrice }}</text></view>
  220 + <view class="row"><text class="label">包装费(元)</text><text class="value">{{ item.packagingFee }}</text></view>
  221 + <view class="row"><text class="label">发货日期</text><text class="value">{{ item.deliveryDate }}</text></view>
  222 + <view class="row"><text class="label">考核超协</text><text class="value">{{ item.assessmentExceedsAgreement }}</text></view>
  223 + <uni-list class="edit-list2">
  224 + <uni-list-item class="select-item" :class="String(item.sampleOrder) ? 'is-filled' : 'is-empty'" clickable
  225 + @click="openSheet(idx)" :rightText="(item.sampleOrder ? '是' : '否') || '请选择'" showArrow>
  226 + <template v-slot:body>
  227 + <view class="item-title"><text>是否为试样订单</text></view>
  228 + </template>
  229 + </uni-list-item>
  230 + </uni-list>
  231 + </view>
  232 +
  233 + <view class="block-ops">
  234 + <div class="toggle" @click="toggleItem(idx)">
  235 + <image :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'"
  236 + class="icon" />
  237 + {{ item.collapsed ? '展开' : '收起' }}
  238 + </div>
  239 + </view>
  240 + </view>
  241 + </view>
  242 +
97 <view v-else-if="mode === 'view'" class="view-list" v-show="!collapsedView"> 243 <view v-else-if="mode === 'view'" class="view-list" v-show="!collapsedView">
98 <view v-for="(item, idx) in items" :key="'v-' + idx" class="card"> 244 <view v-for="(item, idx) in items" :key="'v-' + idx" class="card">
99 <view class="row"><text class="label">行业</text><text class="value">{{ item.industry }}</text></view> 245 <view class="row"><text class="label">行业</text><text class="value">{{ item.industry }}</text></view>
@@ -136,6 +282,7 @@ @@ -136,6 +282,7 @@
136 </view> 282 </view>
137 <view class="row"><text class="label">考核超协</text><text class="value">{{ item.assessmentExceedsAgreement 283 <view class="row"><text class="label">考核超协</text><text class="value">{{ item.assessmentExceedsAgreement
138 }}</text></view> 284 }}</text></view>
  285 + <view class="row"><text class="label">是否为试样订单</text><text class="value">{{ item.sampleOrder ? '是' : '否' }}</text></view>
139 </view> 286 </view>
140 <view class="view-total"> 287 <view class="view-total">
141 <view class="head">合计</view> 288 <view class="head">合计</view>
@@ -145,15 +292,20 @@ @@ -145,15 +292,20 @@
145 </view> 292 </view>
146 </view> 293 </view>
147 294
  295 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
  296 + @confirm="onSheetConfirm" />
148 </view> 297 </view>
149 </template> 298 </template>
150 <script> 299 <script>
151 import { uuid } from '@/utils/uuid.js' 300 import { uuid } from '@/utils/uuid.js'
  301 +import SingleSelectSheet from '@/components/single-select/index.vue'
152 export default { 302 export default {
153 name: 'Product', 303 name: 'Product',
  304 + components: { SingleSelectSheet },
154 props: { 305 props: {
155 title: { type: String, default: '' }, 306 title: { type: String, default: '' },
156 mode: { type: String, default: 'add' }, 307 mode: { type: String, default: 'add' },
  308 + isSampleOrderEdit: { type: Boolean, default: false },
157 list: { type: Array, default: () => [] }, 309 list: { type: Array, default: () => [] },
158 max: { type: Number, default: 8 }, 310 max: { type: Number, default: 8 },
159 totalQuantity: { type: Number, default: 0 }, 311 totalQuantity: { type: Number, default: 0 },
@@ -164,6 +316,7 @@ export default { @@ -164,6 +316,7 @@ export default {
164 return { 316 return {
165 items: [], 317 items: [],
166 collapsedView: false, 318 collapsedView: false,
  319 + sheet: { visible: false, title: '请选择', options: [], value: '', field: '' }
167 } 320 }
168 }, 321 },
169 computed: { 322 computed: {
@@ -215,6 +368,7 @@ export default { @@ -215,6 +368,7 @@ export default {
215 }, 368 },
216 emitChange() { 369 emitChange() {
217 console.log('emitChange__items', this.items) 370 console.log('emitChange__items', this.items)
  371 + console.log('mode__', this.mode)
218 const out = this.items.map(it => JSON.parse(JSON.stringify(it))) 372 const out = this.items.map(it => JSON.parse(JSON.stringify(it)))
219 console.log('emitChange__out', out) 373 console.log('emitChange__out', out)
220 this.$emit('input', out) 374 this.$emit('input', out)
@@ -309,7 +463,22 @@ export default { @@ -309,7 +463,22 @@ export default {
309 const num = Number(v) 463 const num = Number(v)
310 if (isNaN(num) || num < 0) item[field] = '0' 464 if (isNaN(num) || num < 0) item[field] = '0'
311 if (typeof idx === 'number') this.$set(this.items, idx, { ...item }) 465 if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
312 - } 466 + },
  467 + openSheet(idx) {
  468 + const item = this.items[idx]
  469 + const options = [{ label: '是', value: true }, { label: '否', value: false }]
  470 + const current = item.sampleOrder
  471 + this.sheet = { visible: true, title: '是否为试样订单', options, idx, value: current }
  472 + },
  473 + onSheetConfirm({ value }) {
  474 + const idx = this.sheet.idx
  475 + if (idx > -1 && this.items[idx]) {
  476 + const item = this.items[idx]
  477 + item.sampleOrder = value
  478 + this.$set(this.items, idx, { ...item })
  479 + }
  480 + this.sheet.visible = false
  481 + },
313 } 482 }
314 } 483 }
315 </script> 484 </script>
@@ -771,4 +940,10 @@ export default { @@ -771,4 +940,10 @@ export default {
771 } 940 }
772 } 941 }
773 } 942 }
  943 +
  944 +::v-deep .edit-list2 {
  945 + .uni-list--border-top {
  946 + height: 0;
  947 + }
  948 +}
774 </style> 949 </style>
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 <view class="row"><text class="label">备货单位/人(生产标准)</text><text class="value">{{ form.stockUpCompanyName }}</text></view> 16 <view class="row"><text class="label">备货单位/人(生产标准)</text><text class="value">{{ form.stockUpCompanyName }}</text></view>
17 <view class="row"><text class="label">结算方式或期限</text><text class="value">{{ form.settlementTerms }}</text></view> 17 <view class="row"><text class="label">结算方式或期限</text><text class="value">{{ form.settlementTerms }}</text></view>
18 <view class="row"><text class="label">交货方式</text><text class="value">{{ form.deliveryMethod }}</text></view> 18 <view class="row"><text class="label">交货方式</text><text class="value">{{ form.deliveryMethod }}</text></view>
  19 + <view class="row"><text class="label">是否为试样订单</text><text class="value">{{ form.sampleOrder ? '是' : '否' }}</text></view>
19 </view> 20 </view>
20 21
21 <!-- 产品 --> 22 <!-- 产品 -->
@@ -25,7 +26,7 @@ @@ -25,7 +26,7 @@
25 26
26 <view class="section"> 27 <view class="section">
27 <view class="row"><text class="label">价格表编号</text><text class="value">{{ form.priceListNo }}</text></view> 28 <view class="row"><text class="label">价格表编号</text><text class="value">{{ form.priceListNo }}</text></view>
28 - <view class="row"><text class="label">开票情况</text><text class="value">{{ form.invoicingStatus }}</text></view> 29 + <view class="row"><text class="label">开票要求</text><text class="value">{{ form.invoicingStatus }}</text></view>
29 <view class="row"><text class="label">运费</text><text class="value">{{ form.shippingCost }}</text></view> 30 <view class="row"><text class="label">运费</text><text class="value">{{ form.shippingCost }}</text></view>
30 <view class="row"><text class="label">执行标准</text><text class="value">{{ getDicName('APPLICABLE_STANDARD', 31 <view class="row"><text class="label">执行标准</text><text class="value">{{ getDicName('APPLICABLE_STANDARD',
31 form.executionStandard, dicOptions.APPLICABLE_STANDARD) }}</text></view> 32 form.executionStandard, dicOptions.APPLICABLE_STANDARD) }}</text></view>
@@ -12,6 +12,9 @@ import RestockApprovalViewer from '@/pages/replenishment_order/viewer.vue' @@ -12,6 +12,9 @@ import RestockApprovalViewer from '@/pages/replenishment_order/viewer.vue'
12 import RestockApprovalApprove from '@/pages/replenishment_order/approve.vue' 12 import RestockApprovalApprove from '@/pages/replenishment_order/approve.vue'
13 import DraftOrderViewer from '@/pages/draft_order/viewer.vue' 13 import DraftOrderViewer from '@/pages/draft_order/viewer.vue'
14 import DelayedShipmentViewer from '@/pages/delay_invoice/viewer.vue' 14 import DelayedShipmentViewer from '@/pages/delay_invoice/viewer.vue'
  15 +import ConfirmationFormViewer from '@/pages/confirmation_form/viewer.vue'
  16 +import ConfirmationFormApprove from '@/pages/confirmation_form/approve.vue'
  17 +import FollowUpFormViewer from '@/pages/follow_up_form/viewer.vue'
15 18
16 export default function registerComponents(Vue) { 19 export default function registerComponents(Vue) {
17 Vue.component('CustomerDevelopViewer', CustomerDevelopViewer) 20 Vue.component('CustomerDevelopViewer', CustomerDevelopViewer)
@@ -28,4 +31,7 @@ export default function registerComponents(Vue) { @@ -28,4 +31,7 @@ export default function registerComponents(Vue) {
28 Vue.component('RestockApprovalApprove', RestockApprovalApprove) 31 Vue.component('RestockApprovalApprove', RestockApprovalApprove)
29 Vue.component('DraftOrderViewer', DraftOrderViewer) 32 Vue.component('DraftOrderViewer', DraftOrderViewer)
30 Vue.component('DelayedShipmentViewer', DelayedShipmentViewer) 33 Vue.component('DelayedShipmentViewer', DelayedShipmentViewer)
  34 + Vue.component('ConfirmationFormViewer', ConfirmationFormViewer)
  35 + Vue.component('ConfirmationFormApprove', ConfirmationFormApprove)
  36 + Vue.component('FollowUpFormViewer', FollowUpFormViewer)
31 } 37 }
@@ -504,6 +504,8 @@ @@ -504,6 +504,8 @@
504 .uni-list-item__extra-text { 504 .uni-list-item__extra-text {
505 color: $uni-text-color-grey; 505 color: $uni-text-color-grey;
506 font-size: $uni-font-size-sm; 506 font-size: $uni-font-size-sm;
  507 + white-space: pre-wrap;
  508 + word-break: break-all;
507 } 509 }
508 510
509 .uni-ellipsis-1 { 511 .uni-ellipsis-1 {
@@ -79,6 +79,17 @@ export const getSysFlowComponentPath = (bizFlag) => { @@ -79,6 +79,17 @@ export const getSysFlowComponentPath = (bizFlag) => {
79 break; 79 break;
80 case 'DELAYED_SHIPMENT_EDIT': // 延期发货单 80 case 'DELAYED_SHIPMENT_EDIT': // 延期发货单
81 componentPath = 'DelayedShipmentViewer'; // 延期发货单-审批 81 componentPath = 'DelayedShipmentViewer'; // 延期发货单-审批
  82 + case 'CONFIRMATION_SLIP': // 产品试样确认单
  83 + componentPath = 'ConfirmationFormViewer'; // 产品试样确认单-审批详情
  84 + break;
  85 + case 'CONFIRMATION_SLIP_EDIT': // 产品试样确认单
  86 + componentPath = 'ConfirmationFormApprove'; // 产品试样确认单-审批
  87 + break;
  88 + case 'RESULT_TRACKING': // 产品试样跟踪单
  89 + componentPath = 'FollowUpFormViewer'; // 产品试样跟踪单-审批详情
  90 + break;
  91 + case 'RESULT_TRACKING_EDIT': // 产品试样跟踪单
  92 + componentPath = 'FollowUpFormViewer'; // 产品试样跟踪单-审批
82 break; 93 break;
83 } 94 }
84 return componentPath; 95 return componentPath;