Commit 40195402fc9fb10d5165c649e42b25871e0e61d5

Authored by gesilong
2 parents ed46d051 64085952

Merge branch 'cjerp-1.0_20260116' of http://gitlab.qgutech.com/zhuyuanliang/erp-…

…mobile into cjerp-1.0_20260116
1 import request from '@/utils/request' 1 import request from '@/utils/request'
2 -import { ContentTypeEnum } from '@/utils/httpEnum';  
3 import config from '@/config' 2 import config from '@/config'
4 import { getToken } from '@/utils/auth' 3 import { getToken } from '@/utils/auth'
5 4
@@ -32,6 +31,20 @@ export function uploadFileApi(data) { @@ -32,6 +31,20 @@ export function uploadFileApi(data) {
32 } 31 }
33 32
34 /** 33 /**
  34 + * 下载文件通用接口
  35 + * @param id
  36 + */
  37 +export function downloadFileApi(id) {
  38 + return request({
  39 + url: `/download/security/url`,
  40 + method: 'get',
  41 + params: {
  42 + id
  43 + },
  44 + })
  45 +}
  46 +
  47 +/**
35 * 回去城市接口 省市区 一次性返回 48 * 回去城市接口 省市区 一次性返回
36 */ 49 */
37 export function selectorCityApi() { 50 export function selectorCityApi() {
@@ -63,4 +76,4 @@ export function generateCodeApi(type) { @@ -63,4 +76,4 @@ export function generateCodeApi(type) {
63 type 76 type
64 }, 77 },
65 }) 78 })
66 -}  
  79 +}
  1 +<template>
  2 + <uni-popup ref="popup" type="bottom" :mask-click="false" :safe-area="true">
  3 + <view class="sheet">
  4 + <view class="sheet-header">
  5 + <text class="cancel" @click="onCancel">取消</text>
  6 + <text class="title">{{ title }}</text>
  7 + <text class="ok" @click="onConfirm">确认</text>
  8 + </view>
  9 + <view class="sheet-body">
  10 + <view
  11 + v-for="(opt, i) in options"
  12 + :key="i"
  13 + :class="['option', { selected: isSelected(opt) }]"
  14 + @click="toggle(opt)"
  15 + >
  16 + <text class="label">{{ displayOf(opt) }}</text>
  17 + </view>
  18 + </view>
  19 + </view>
  20 + </uni-popup>
  21 +</template>
  22 +
  23 +<script>
  24 +export default {
  25 + name: 'MultiSelectSheet',
  26 + props: {
  27 + visible: { type: Boolean, default: false },
  28 + title: { type: String, default: '请选择' },
  29 + // 统一约定:options 为 [{ label: string, value: string|number }]
  30 + options: { type: Array, default: () => [] },
  31 + // 接收逗号分隔的字符串 '111,222,333'
  32 + value: { type: String, default: '' }
  33 + },
  34 + data() {
  35 + return {
  36 + innerValue: [] // 内部维护数组形式
  37 + }
  38 + },
  39 + watch: {
  40 + value(v) { this.initInnerValue(v) },
  41 + visible(v) { v ? this.open() : this.close() }
  42 + },
  43 + mounted() {
  44 + if (this.visible) this.open()
  45 + },
  46 + methods: {
  47 + initInnerValue(val) {
  48 + if (!val) {
  49 + this.innerValue = []
  50 + } else {
  51 + this.innerValue = String(val).split(',').filter(x => x)
  52 + }
  53 + },
  54 + open() {
  55 + this.initInnerValue(this.value)
  56 + this.$refs.popup && this.$refs.popup.open()
  57 + this.$emit('update:visible', true)
  58 + },
  59 + close() {
  60 + this.$refs.popup && this.$refs.popup.close()
  61 + this.$emit('update:visible', false)
  62 + },
  63 + displayOf(opt) {
  64 + if (!opt) return ''
  65 + return opt.label != null ? String(opt.label) : ''
  66 + },
  67 + valueOf(opt) {
  68 + if (!opt) return ''
  69 + return opt.value != null ? String(opt.value) : ''
  70 + },
  71 + isSelected(opt) {
  72 + const v = this.valueOf(opt)
  73 + return this.innerValue.includes(v)
  74 + },
  75 + toggle(opt) {
  76 + const v = this.valueOf(opt)
  77 + const idx = this.innerValue.indexOf(v)
  78 + if (idx > -1) {
  79 + this.innerValue.splice(idx, 1)
  80 + } else {
  81 + this.innerValue.push(v)
  82 + }
  83 + },
  84 + onCancel() {
  85 + this.close()
  86 + this.$emit('cancel')
  87 + },
  88 + onConfirm() {
  89 + const selectedValues = this.innerValue
  90 + // 保持原始选项顺序
  91 + const sortedValues = []
  92 + const sortedLabels = []
  93 +
  94 + this.options.forEach(opt => {
  95 + const v = this.valueOf(opt)
  96 + if (selectedValues.includes(v)) {
  97 + sortedValues.push(v)
  98 + sortedLabels.push(this.displayOf(opt))
  99 + }
  100 + })
  101 +
  102 + const valStr = sortedValues.join(',')
  103 + const labelStr = sortedLabels.join(',')
  104 +
  105 + this.$emit('confirm', { value: valStr, label: labelStr })
  106 + this.$emit('input', valStr)
  107 + this.$emit('update:value', valStr)
  108 + this.close()
  109 + }
  110 + }
  111 +}
  112 +</script>
  113 +
  114 +<style lang="scss" scoped>
  115 +.sheet {
  116 + width: 100%;
  117 + max-height: 45vh;
  118 + background: #fff;
  119 + border-radius: 20rpx 20rpx 0 0;
  120 + display: flex;
  121 + flex-direction: column;
  122 +}
  123 +.sheet-header {
  124 + display: flex;
  125 + align-items: center;
  126 + justify-content: space-between;
  127 + padding: 30rpx 32rpx;
  128 + border-bottom: 1rpx solid #f0f0f0;
  129 +}
  130 +.title {
  131 + font-size: 36rpx;
  132 + font-weight: 600;
  133 +}
  134 +.cancel {
  135 + color: rgba(0,0,0,0.6);
  136 + font-size: 28rpx;
  137 +}
  138 +.ok {
  139 + color: $theme-primary;
  140 + font-size: 28rpx;
  141 +}
  142 +.sheet-body {
  143 + flex: 1 1 auto;
  144 + overflow-y: auto;
  145 + padding: 32rpx;
  146 +}
  147 +.option {
  148 + padding: 20rpx;
  149 + line-height: 40rpx;
  150 + background: #fff;
  151 + text-align: center;
  152 + border-radius: 12rpx;
  153 + font-size: 32rpx;
  154 + margin-bottom: 20rpx;
  155 + .label {
  156 + color: rgba(0,0,0,0.6);
  157 + font-size: 32rpx;
  158 + }
  159 + &.selected {
  160 + background: #f3f3f3;
  161 + .label {
  162 + color: rgba(0,0,0,0.9);
  163 + }
  164 + }
  165 +}
  166 +</style>
@@ -300,6 +300,8 @@ export default { @@ -300,6 +300,8 @@ export default {
300 font-size: 28rpx; 300 font-size: 28rpx;
301 color: rgba(0, 0, 0, 0.9); 301 color: rgba(0, 0, 0, 0.9);
302 text-align: right; 302 text-align: right;
  303 + white-space: pre-wrap;
  304 + word-break: break-all;
303 305
304 &.act { 306 &.act {
305 color: $theme-primary; 307 color: $theme-primary;
@@ -49,6 +49,8 @@ @@ -49,6 +49,8 @@
49 49
50 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" 50 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
51 @confirm="onSheetConfirm" /> 51 @confirm="onSheetConfirm" />
  52 + <MultiSelectSheet :visible.sync="multiSheet.visible" :title="multiSheet.title" :options="multiSheet.options" v-model="multiSheet.value"
  53 + @confirm="onMultiSheetConfirm" />
52 54
53 <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source" 55 <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source"
54 :display-fields="relate.display" :multiple="relate.multiple" :row-key="relate.rowKey" 56 :display-fields="relate.display" :multiple="relate.multiple" :row-key="relate.rowKey"
@@ -57,12 +59,13 @@ @@ -57,12 +59,13 @@
57 </template> 59 </template>
58 <script> 60 <script>
59 import SingleSelectSheet from '@/components/single-select/index.vue' 61 import SingleSelectSheet from '@/components/single-select/index.vue'
  62 +import MultiSelectSheet from '@/components/multi-select/index.vue'
60 import RelateSelectSheet from '@/components/relate-select/index.vue' 63 import RelateSelectSheet from '@/components/relate-select/index.vue'
61 import { productVarietyQuery, getCodeApi, createApi } from '@/api/contract' 64 import { productVarietyQuery, getCodeApi, createApi } from '@/api/contract'
62 import { getDicByCodes } from '@/utils/dic' 65 import { getDicByCodes } from '@/utils/dic'
63 66
64 export default { 67 export default {
65 - components: { SingleSelectSheet, RelateSelectSheet }, 68 + components: { SingleSelectSheet, RelateSelectSheet, MultiSelectSheet },
66 data() { 69 data() {
67 return { 70 return {
68 form: { 71 form: {
@@ -80,6 +83,7 @@ export default { @@ -80,6 +83,7 @@ export default {
80 productVarietyList: [], 83 productVarietyList: [],
81 companyList: [], 84 companyList: [],
82 sheet: { visible: false, title: '请选择', field: '', options: [], value: '' }, 85 sheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
  86 + multiSheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
83 relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' } 87 relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' }
84 } 88 }
85 }, 89 },
@@ -132,14 +136,25 @@ export default { @@ -132,14 +136,25 @@ export default {
132 const match = (options || []).find(o => String(o.label) === String(current) || String(o.value) === String(current)) 136 const match = (options || []).find(o => String(o.label) === String(current) || String(o.value) === String(current))
133 this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' } 137 this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
134 } 138 }
  139 + const setMultiSheet = (title, options) => {
  140 + const current = this.form[field]
  141 + this.multiSheet = { ...this.multiSheet, visible: true, title, options, field, value: current || '' }
  142 + }
  143 +
135 if (field === 'company') { 144 if (field === 'company') {
136 setSheet('所属单位', this.companyList) 145 setSheet('所属单位', this.companyList)
137 } else if (field === 'materialTypeId') { 146 } else if (field === 'materialTypeId') {
138 - setSheet('品种', this.productVarietyList) 147 + setMultiSheet('品种', this.productVarietyList)
139 } else if (field === 'hasFrameworkAgreement') { 148 } else if (field === 'hasFrameworkAgreement') {
140 setSheet('是否签订框架合同', [{ label: '是', value: true }, { label: '否', value: false }]) 149 setSheet('是否签订框架合同', [{ label: '是', value: true }, { label: '否', value: false }])
141 } 150 }
142 }, 151 },
  152 + onMultiSheetConfirm({ value, label }) {
  153 + const field = this.multiSheet.field
  154 + if (!field) return
  155 + this.form[field] = value || ''
  156 + this.form[field + 'Name'] = label || ''
  157 + },
143 onSheetConfirm({ value, label }) { 158 onSheetConfirm({ value, label }) {
144 const field = this.sheet.field 159 const field = this.sheet.field
145 if (!field) return 160 if (!field) return
@@ -49,6 +49,8 @@ @@ -49,6 +49,8 @@
49 49
50 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" 50 <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
51 @confirm="onSheetConfirm" /> 51 @confirm="onSheetConfirm" />
  52 + <MultiSelectSheet :visible.sync="multiSheet.visible" :title="multiSheet.title" :options="multiSheet.options" v-model="multiSheet.value"
  53 + @confirm="onMultiSheetConfirm" />
52 <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source" 54 <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source"
53 :display-fields="relate.display" :multiple="relate.multiple" :row-key="relate.rowKey" 55 :display-fields="relate.display" :multiple="relate.multiple" :row-key="relate.rowKey"
54 :selectedKeys.sync="relate.selectedKeys" @confirm="onRelateConfirm" /> 56 :selectedKeys.sync="relate.selectedKeys" @confirm="onRelateConfirm" />
@@ -57,12 +59,13 @@ @@ -57,12 +59,13 @@
57 59
58 <script> 60 <script>
59 import SingleSelectSheet from '@/components/single-select/index.vue' 61 import SingleSelectSheet from '@/components/single-select/index.vue'
  62 +import MultiSelectSheet from '@/components/multi-select/index.vue'
60 import RelateSelectSheet from '@/components/relate-select/index.vue' 63 import RelateSelectSheet from '@/components/relate-select/index.vue'
61 import { productVarietyQuery, getCodeApi, getDetailApi, updateApi } from '@/api/contract' 64 import { productVarietyQuery, getCodeApi, getDetailApi, updateApi } from '@/api/contract'
62 import { getDicByCodes } from '@/utils/dic' 65 import { getDicByCodes } from '@/utils/dic'
63 66
64 export default { 67 export default {
65 - components: { SingleSelectSheet, RelateSelectSheet }, 68 + components: { SingleSelectSheet, RelateSelectSheet, MultiSelectSheet },
66 data() { 69 data() {
67 return { 70 return {
68 id: '', 71 id: '',
@@ -70,6 +73,7 @@ export default { @@ -70,6 +73,7 @@ export default {
70 companyList: [], 73 companyList: [],
71 productVarietyList: [], 74 productVarietyList: [],
72 sheet: { visible: false, title: '请选择', field: '', options: [], value: '' }, 75 sheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
  76 + multiSheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
73 relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' } 77 relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' }
74 } 78 }
75 }, 79 },
@@ -122,10 +126,21 @@ export default { @@ -122,10 +126,21 @@ export default {
122 const match = (options || []).find(o => String(o.value) === String(current)) 126 const match = (options || []).find(o => String(o.value) === String(current))
123 this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' } 127 this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
124 } 128 }
  129 + const setMultiSheet = (title, options) => {
  130 + const current = this.form[field]
  131 + this.multiSheet = { ...this.multiSheet, visible: true, title, options, field, value: current || '' }
  132 + }
  133 +
125 if (field === 'company') setSheet('所属单位', this.companyList) 134 if (field === 'company') setSheet('所属单位', this.companyList)
126 - else if (field === 'materialTypeId') setSheet('品种', this.productVarietyList) 135 + else if (field === 'materialTypeId') setMultiSheet('品种', this.productVarietyList)
127 else if (field === 'hasFrameworkAgreement') setSheet('是否签订框架合同', [{ label: '是', value: true }, { label: '否', value: false }]) 136 else if (field === 'hasFrameworkAgreement') setSheet('是否签订框架合同', [{ label: '是', value: true }, { label: '否', value: false }])
128 }, 137 },
  138 + onMultiSheetConfirm({ value, label }) {
  139 + const field = this.multiSheet.field
  140 + if (!field) return
  141 + this.form[field] = value || ''
  142 + this.form[field + 'Name'] = label || ''
  143 + },
129 onSheetConfirm({ value, label }) { 144 onSheetConfirm({ value, label }) {
130 const field = this.sheet.field 145 const field = this.sheet.field
131 if (!field) return 146 if (!field) return
@@ -32,9 +32,9 @@ @@ -32,9 +32,9 @@
32 <view class="row"><text class="label">经营年限</text><text class="value">{{ form.businessYears }}</text></view> 32 <view class="row"><text class="label">经营年限</text><text class="value">{{ form.businessYears }}</text></view>
33 <view class="row"><text class="label">单位地址</text><text class="value">{{ form.companyAddress }}</text></view> 33 <view class="row"><text class="label">单位地址</text><text class="value">{{ form.companyAddress }}</text></view>
34 <view class="row"><text class="label">经营范围</text><text class="value">{{ form.businessScope }}</text></view> 34 <view class="row"><text class="label">经营范围</text><text class="value">{{ form.businessScope }}</text></view>
35 - <view class="row"><text class="label">工商信息</text><text class="value act">{{ form.businessFileName }}</text> 35 + <view class="row"><text class="label">工商信息</text><text class="value act" @click="downloadFile(form.businessFileId, form.businessFileName)">{{ form.businessFileName }}</text>
36 </view> 36 </view>
37 - <view class="row"><text class="label">股东信息</text><text class="value act">{{ form.shareholderFileName }}</text> 37 + <view class="row"><text class="label">股东信息</text><text class="value act" @click="downloadFile(form.shareholderFileId, form.shareholderFileName)">{{ form.shareholderFileName }}</text>
38 </view> 38 </view>
39 </view> 39 </view>
40 40
@@ -174,6 +174,7 @@ @@ -174,6 +174,7 @@
174 <script> 174 <script>
175 import { getDetailApi, getByIdCreditHistoryList, cancelApi } from '@/api/credit_manage.js' 175 import { getDetailApi, getByIdCreditHistoryList, cancelApi } from '@/api/credit_manage.js'
176 import { getDicName } from '@/utils/dic.js' 176 import { getDicName } from '@/utils/dic.js'
  177 +import { downloadFile } from '@/utils/downloadFile.js'
177 import { getDicByCodeApi } from '@/api/base.js' 178 import { getDicByCodeApi } from '@/api/base.js'
178 import CorePersonnel from './corePersonnel.vue' 179 import CorePersonnel from './corePersonnel.vue'
179 import DetailButtons from '@/components/detail-buttons/index.vue' 180 import DetailButtons from '@/components/detail-buttons/index.vue'
@@ -350,6 +351,7 @@ export default { @@ -350,6 +351,7 @@ export default {
350 }) 351 })
351 }, 352 },
352 getDicName, 353 getDicName,
  354 + downloadFile,
353 getCategoryClass(categoryName) { 355 getCategoryClass(categoryName) {
354 if (!categoryName) return '' 356 if (!categoryName) return ''
355 if (categoryName.includes('A') || categoryName.includes('a')) { 357 if (categoryName.includes('A') || categoryName.includes('a')) {
@@ -30,9 +30,9 @@ @@ -30,9 +30,9 @@
30 <view class="row"><text class="label">经营年限</text><text class="value">{{ form.businessYears }}</text></view> 30 <view class="row"><text class="label">经营年限</text><text class="value">{{ form.businessYears }}</text></view>
31 <view class="row"><text class="label">单位地址</text><text class="value">{{ form.companyAddress }}</text></view> 31 <view class="row"><text class="label">单位地址</text><text class="value">{{ form.companyAddress }}</text></view>
32 <view class="row"><text class="label">经营范围</text><text class="value">{{ form.businessScope }}</text></view> 32 <view class="row"><text class="label">经营范围</text><text class="value">{{ form.businessScope }}</text></view>
33 - <view class="row"><text class="label">工商信息</text><text class="value act">{{ form.businessFileName }}</text> 33 + <view class="row"><text class="label">工商信息</text><text class="value act" @click="downloadFile(form.businessFileId, form.businessFileName)">{{ form.businessFileName }}</text>
34 </view> 34 </view>
35 - <view class="row"><text class="label">股东信息</text><text class="value act">{{ form.shareholderFileName 35 + <view class="row"><text class="label">股东信息</text><text class="value act" @click="downloadFile(form.shareholderFileId, form.shareholderFileName)">{{ form.shareholderFileName
36 }}</text> 36 }}</text>
37 </view> 37 </view>
38 </view> 38 </view>
@@ -180,6 +180,7 @@ import { getExamineById, getByIdExamineCustomerCreditHistoryList } from '@/api/c @@ -180,6 +180,7 @@ import { getExamineById, getByIdExamineCustomerCreditHistoryList } from '@/api/c
180 import { getDicName } from '@/utils/dic.js' 180 import { getDicName } from '@/utils/dic.js'
181 import { getDicByCodeApi } from '@/api/base.js' 181 import { getDicByCodeApi } from '@/api/base.js'
182 import CorePersonnel from './corePersonnel.vue' 182 import CorePersonnel from './corePersonnel.vue'
  183 +import { downloadFile } from '@/utils/downloadFile.js'
183 184
184 export default { 185 export default {
185 name: 'CustomerCreditApprove', 186 name: 'CustomerCreditApprove',
@@ -274,6 +275,7 @@ export default { @@ -274,6 +275,7 @@ export default {
274 uni.navigateTo({ url: '/pages/credit_manage/history_detail' + query }) 275 uni.navigateTo({ url: '/pages/credit_manage/history_detail' + query })
275 }, 276 },
276 getDicName, 277 getDicName,
  278 + downloadFile,
277 getCategoryClass(categoryName) { 279 getCategoryClass(categoryName) {
278 if (!categoryName) return '' 280 if (!categoryName) return ''
279 if (categoryName.includes('A') || categoryName.includes('a')) { 281 if (categoryName.includes('A') || categoryName.includes('a')) {
@@ -41,9 +41,9 @@ @@ -41,9 +41,9 @@
41 </uni-list-item> 41 </uni-list-item>
42 42
43 <!-- 其余输入项 --> 43 <!-- 其余输入项 -->
44 - <uni-list-item title="月用量"> 44 + <uni-list-item title="月用量(吨)">
45 <template v-slot:footer> 45 <template v-slot:footer>
46 - <uni-easyinput v-model="form.monthlyUsage" placeholder="请输入月用量" :inputBorder="false" /> 46 + <uni-easyinput v-model="form.monthlyUsage" placeholder="请输入月用量(吨)" :inputBorder="false" />
47 </template> 47 </template>
48 </uni-list-item> 48 </uni-list-item>
49 <uni-list-item title="目标量"> 49 <uni-list-item title="目标量">
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 </view> 16 </view>
17 <view class="row"><text class="label">产品品种</text><text class="value">{{ form.productVariety.name 17 <view class="row"><text class="label">产品品种</text><text class="value">{{ form.productVariety.name
18 }}</text></view> 18 }}</text></view>
19 - <view class="row"><text class="label">月用量</text><text class="value">{{ form.monthlyUsage }}</text> 19 + <view class="row"><text class="label">月用量(吨)</text><text class="value">{{ form.monthlyUsage }}</text>
20 </view> 20 </view>
21 <view class="row"><text class="label">目标量</text><text class="value">{{ form.targetQuantity }}</text> 21 <view class="row"><text class="label">目标量</text><text class="value">{{ form.targetQuantity }}</text>
22 </view> 22 </view>
@@ -41,9 +41,9 @@ @@ -41,9 +41,9 @@
41 </uni-list-item> 41 </uni-list-item>
42 42
43 <!-- 其余输入项 --> 43 <!-- 其余输入项 -->
44 - <uni-list-item title="月用量"> 44 + <uni-list-item title="月用量(吨)">
45 <template v-slot:footer> 45 <template v-slot:footer>
46 - <uni-easyinput v-model="form.monthlyUsage" placeholder="请输入月用量" :inputBorder="false" /> 46 + <uni-easyinput v-model="form.monthlyUsage" placeholder="请输入月用量(吨)" :inputBorder="false" />
47 </template> 47 </template>
48 </uni-list-item> 48 </uni-list-item>
49 <uni-list-item title="目标量"> 49 <uni-list-item title="目标量">
@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 </view> 13 </view>
14 <view class="row"><text class="label">产品品种</text><text class="value">{{ form.productVariety.name }}</text> 14 <view class="row"><text class="label">产品品种</text><text class="value">{{ form.productVariety.name }}</text>
15 </view> 15 </view>
16 - <view class="row"><text class="label">月用量</text><text class="value">{{ form.monthlyUsage }}</text> 16 + <view class="row"><text class="label">月用量(吨)</text><text class="value">{{ form.monthlyUsage }}</text>
17 </view> 17 </view>
18 <view class="row"><text class="label">目标量</text><text class="value">{{ form.targetQuantity }}</text> 18 <view class="row"><text class="label">目标量</text><text class="value">{{ form.targetQuantity }}</text>
19 </view> 19 </view>
@@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
19 @split="splitFun" /> 19 @split="splitFun" />
20 </view> 20 </view>
21 <view class="section"> 21 <view class="section">
22 - <view class="row"><text class="label">签收单据</text><text class="value act">{{ form.fileName }}</text></view> 22 + <view class="row"><text class="label">签收单据</text><text class="value act" @click="downloadFile(form.fileId, form.fileName)">{{ form.fileName }}</text></view>
23 </view> 23 </view>
24 </view> 24 </view>
25 </scroll-view> 25 </scroll-view>
@@ -141,6 +141,7 @@ import Product from './product.vue' @@ -141,6 +141,7 @@ import Product from './product.vue'
141 import DetailButtons from '@/components/detail-buttons/index.vue' 141 import DetailButtons from '@/components/detail-buttons/index.vue'
142 import FileUpload from '@/components/file-upload/index.vue' 142 import FileUpload from '@/components/file-upload/index.vue'
143 import { getShipmentPlanDetailApi, createApi } from '@/api/delay_invoice.js' 143 import { getShipmentPlanDetailApi, createApi } from '@/api/delay_invoice.js'
  144 +import { downloadFile } from '@/utils/downloadFile.js'
144 145
145 export default { 146 export default {
146 name: 'InvoiceDetail', 147 name: 'InvoiceDetail',
@@ -220,6 +221,7 @@ export default { @@ -220,6 +221,7 @@ export default {
220 onUpload() { 221 onUpload() {
221 this.$refs.uploadPopup && this.$refs.uploadPopup.open() 222 this.$refs.uploadPopup && this.$refs.uploadPopup.open()
222 }, 223 },
  224 + downloadFile,
223 closeUploadInfo() { 225 closeUploadInfo() {
224 this.uploadFile = { id: '', name: '' }; 226 this.uploadFile = { id: '', name: '' };
225 this.$refs.uploadPopup && this.$refs.uploadPopup.close() 227 this.$refs.uploadPopup && this.$refs.uploadPopup.close()
@@ -95,9 +95,9 @@ export default { @@ -95,9 +95,9 @@ export default {
95 } 95 }
96 }, 96 },
97 created() { 97 created() {
98 - const [start, end] = this.getDefaultDateRange()  
99 - this.filterForm.dateRange = [start, end]  
100 - this.query = { readed: this.filterForm.readed, dateRange: [start, end] } 98 + // 初始化时清空时间筛选,不设置默认值
  99 + this.filterForm.dateRange = []
  100 + this.query = { readed: this.filterForm.readed, dateRange: [] }
101 }, 101 },
102 onReachBottom() { 102 onReachBottom() {
103 if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) { 103 if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) {
@@ -111,19 +111,6 @@ export default { @@ -111,19 +111,6 @@ export default {
111 } 111 }
112 }, 112 },
113 methods: { 113 methods: {
114 - // 默认日期范围:当前日期前一个月到今日  
115 - getDefaultDateRange() {  
116 - const fmt = d => {  
117 - const y = d.getFullYear()  
118 - const m = String(d.getMonth() + 1).padStart(2, '0')  
119 - const dd = String(d.getDate()).padStart(2, '0')  
120 - return `${y}-${m}-${dd}`  
121 - }  
122 - const end = new Date()  
123 - const start = new Date(end)  
124 - start.setMonth(start.getMonth() - 1)  
125 - return [fmt(start), fmt(end)]  
126 - },  
127 onCardLoaded({ items }) { 114 onCardLoaded({ items }) {
128 this.currentItems = items 115 this.currentItems = items
129 }, 116 },
@@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
22 </view> 22 </view>
23 23
24 <view class="section"> 24 <view class="section">
25 - <view class="row"><text class="label">撤销确认凭证</text><text class="value act">{{ form.confirmationVoucherFileName }}</text></view> 25 + <view class="row"><text class="label">撤销确认凭证</text><text class="value act" @click="downloadFile(form.confirmationVoucherFileId, form.confirmationVoucherFileName)">{{ form.confirmationVoucherFileName }}</text></view>
26 </view> 26 </view>
27 </view> 27 </view>
28 </scroll-view> 28 </scroll-view>
@@ -34,6 +34,7 @@ @@ -34,6 +34,7 @@
34 import { getDetailApi, cancelApi } from '@/api/revoke_list.js' 34 import { getDetailApi, cancelApi } from '@/api/revoke_list.js'
35 import Product from './product.vue' 35 import Product from './product.vue'
36 import DetailButtons from '@/components/detail-buttons/index.vue' 36 import DetailButtons from '@/components/detail-buttons/index.vue'
  37 +import { downloadFile } from '@/utils/downloadFile.js'
37 38
38 export default { 39 export default {
39 name: 'RevokeListDetail', 40 name: 'RevokeListDetail',
@@ -111,6 +112,7 @@ export default { @@ -111,6 +112,7 @@ export default {
111 uni.setStorageSync(CACHE_KEY, this.getBusinessId()) 112 uni.setStorageSync(CACHE_KEY, this.getBusinessId())
112 uni.navigateTo({ url: '/pages/flow/audit_detail' }) 113 uni.navigateTo({ url: '/pages/flow/audit_detail' })
113 }, 114 },
  115 + downloadFile,
114 onAudit() { 116 onAudit() {
115 const CACHE_KEY = 'sourceBusinessId' 117 const CACHE_KEY = 'sourceBusinessId'
116 uni.setStorageSync(CACHE_KEY, this.getBusinessId()) 118 uni.setStorageSync(CACHE_KEY, this.getBusinessId())
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 </view> 20 </view>
21 21
22 <view class="section"> 22 <view class="section">
23 - <view class="row"><text class="label">撤销确认凭证</text><text class="value act">{{ form.confirmationVoucherFileName }}</text></view> 23 + <view class="row"><text class="label">撤销确认凭证</text><text class="value act" @click="downloadFile(form.confirmationVoucherFileId, form.confirmationVoucherFileName)">{{ form.confirmationVoucherFileName }}</text></view>
24 </view> 24 </view>
25 25
26 </view> 26 </view>
@@ -29,6 +29,7 @@ @@ -29,6 +29,7 @@
29 <script> 29 <script>
30 import { getDetailApi } from '@/api/revoke_list.js' 30 import { getDetailApi } from '@/api/revoke_list.js'
31 import Product from './product.vue' 31 import Product from './product.vue'
  32 +import { downloadFile } from '@/utils/downloadFile.js'
32 33
33 export default { 34 export default {
34 name: 'RevokeListViewer', 35 name: 'RevokeListViewer',
@@ -61,6 +62,7 @@ export default { @@ -61,6 +62,7 @@ export default {
61 this.form = {} 62 this.form = {}
62 } 63 }
63 }, 64 },
  65 + downloadFile,
64 getFormValues() { 66 getFormValues() {
65 const m = this.form || {} 67 const m = this.form || {}
66 return JSON.parse(JSON.stringify(m)) 68 return JSON.parse(JSON.stringify(m))
  1 +
  2 +import { downloadFileApi } from '@/api/base.js'
  3 +import { getToken } from '@/utils/auth.js'
  4 +
  5 +/**
  6 + * 下载文件通用方法
  7 + * @param id
  8 + * @param fileName
  9 + */
  10 +export async function downloadFile(id, fileName) {
  11 + if (!id) return
  12 + uni.showLoading({ title: '下载中' })
  13 + try {
  14 + const res = await downloadFileApi(id);
  15 + console.log('downloadFileApi__res', res)
  16 + let url = res.data
  17 + if (url) {
  18 + // #ifdef H5
  19 + // H5环境(包括微信、钉钉等)直接跳转可能不带header,需要把token拼接到url上
  20 + const token = getToken()
  21 + if (token) {
  22 + const separator = url.includes('?') ? '&' : '?'
  23 + url = `${url}${separator}X-Auth-Token=${token}`
  24 + }
  25 + // #endif
  26 +
  27 + // 统一使用 uni.downloadFile 下载,解决微信浏览器“在浏览器打开”的提示问题
  28 + uni.downloadFile({
  29 + url,
  30 + success: (res) => {
  31 + if (res.statusCode === 200) {
  32 + const filePath = res.tempFilePath
  33 +
  34 + // #ifdef H5
  35 + const ua = navigator.userAgent.toLowerCase()
  36 + const isAndroid = ua.indexOf('android') > -1 || ua.indexOf('adr') > -1
  37 + const isWeChat = ua.indexOf('micromessenger') !== -1
  38 +
  39 + if (isWeChat && isAndroid) {
  40 + // 安卓微信环境:提示用户去浏览器下载
  41 + // 注意:Blob URL在外部浏览器无法访问,所以这里必须使用原始的 url (带token)
  42 + // 重新构建带token的原始url
  43 + let downloadUrl = url
  44 + // 这里我们假设 url 变量在上面已经被处理过(拼接了token),如果没有,重新拼接
  45 + if (!downloadUrl.includes('X-Auth-Token')) {
  46 + const token = getToken()
  47 + if (token) {
  48 + const separator = downloadUrl.includes('?') ? '&' : '?'
  49 + downloadUrl = `${downloadUrl}${separator}X-Auth-Token=${token}`
  50 + }
  51 + }
  52 +
  53 + uni.showModal({
  54 + title: '提示',
  55 + content: '微信环境下不支持直接下载,请复制链接后在浏览器打开下载',
  56 + confirmText: '复制链接',
  57 + showCancel: false,
  58 + success: function (res) {
  59 + if (res.confirm) {
  60 + uni.setClipboardData({
  61 + data: downloadUrl,
  62 + success: function () {
  63 + uni.showToast({ title: '链接已复制', icon: 'success' })
  64 + }
  65 + })
  66 + }
  67 + }
  68 + })
  69 + } else {
  70 + // 其他环境(iOS微信、普通浏览器)使用a标签下载
  71 + const link = document.createElement('a')
  72 + link.href = filePath
  73 + link.download = fileName || 'download'
  74 + document.body.appendChild(link)
  75 + link.click()
  76 + document.body.removeChild(link)
  77 + }
  78 + // #endif
  79 +
  80 + // #ifndef H5
  81 + const fileType = fileName ? fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase() : ''
  82 + uni.openDocument({
  83 + filePath,
  84 + fileType: fileType || undefined,
  85 + showMenu: true,
  86 + success: function () {
  87 + console.log('打开文档成功')
  88 + },
  89 + fail: function (err) {
  90 + console.error('打开文档失败', err)
  91 + uni.showToast({ title: '无法打开此文件', icon: 'none' })
  92 + }
  93 + })
  94 + // #endif
  95 + } else {
  96 + uni.showToast({ title: '下载失败', icon: 'none' })
  97 + }
  98 + },
  99 + fail: (err) => {
  100 + console.error('下载失败', err)
  101 + uni.showToast({ title: '下载失败', icon: 'none' })
  102 + }
  103 + })
  104 + } else {
  105 + uni.showToast({ title: '文件地址无效', icon: 'none' })
  106 + }
  107 + } catch (e) {
  108 + console.error(e)
  109 + uni.showToast({ title: '下载出错', icon: 'none' })
  110 + } finally {
  111 + uni.hideLoading()
  112 + }
  113 +}