Pārlūkot izejas kodu

数字交接功能

seimin 2 gadi atpakaļ
vecāks
revīzija
76f45f556c

+ 1 - 2
components/bigScreen/bigScreen.vue

@@ -82,8 +82,7 @@
82 82
                         });
83 83
                       } else if (res.type == "quickOrder") {
84 84
                         //快捷建单
85
-                        res.isDigitalHandover = 1;
86
-                        if(res.isDigitalHandover == 1){
85
+                        if(res.data.isDigitalHandover == 1){
87 86
                           uni.navigateTo({
88 87
                             url: `../specimenChecking/specimenChecking?infoDATA=${encodeURIComponent(
89 88
                             JSON.stringify(res.data)

+ 302 - 0
components/changeSpeNum/changeSpeNum.vue

@@ -0,0 +1,302 @@
1
+<template>
2
+  <view class="changeSpeNum" v-show="disjunctor">
3
+    <view class="changeSpeNum__wrap">
4
+      <view class="changeSpeNum__header" v-if="title">
5
+        {{ title }}
6
+      </view>
7
+      <view class="changeSpeNum__article">
8
+        <view class="uni-list-cell">
9
+          <view class="uni-list-cell-left">
10
+            标本数量:
11
+          </view>
12
+          <view class="uni-list-cell-db">
13
+            <uni-number-box v-model="speNum"></uni-number-box>
14
+          </view>
15
+        </view>
16
+        <view class="uni-list-cell" v-if="speNum != num">
17
+          <view class="uni-list-cell-left">
18
+            修改原因:
19
+          </view>
20
+          <view class="uni-list-cell-db-text">
21
+            <textarea placeholder="请填写修改原因" v-model="reason" />
22
+          </view>
23
+        </view>
24
+        <view class="uni-list-cell" v-if="speNum != num">
25
+          <view class="uni-list-cell-left">
26
+            上传图片:
27
+          </view>
28
+          <view class="uni-list-cell-db">
29
+            <uni-file-picker :auto-upload="false" :limit="3" title="最多选择3张图片" v-model="imageValue" fileMediatype="image" mode="grid"
30
+              @select="selectFile" @delete="deleteFile"></uni-file-picker>
31
+          </view>
32
+        </view>
33
+      </view>
34
+      <view class="changeSpeNum__footer">
35
+        <view v-if="operate.ok" class="changeSpeNum__ok" @click="ok" hover-class="seimin-btn-hover">
36
+          {{ operate.ok || "" }}
37
+        </view>
38
+        <view v-if="operate.cancel" class="changeSpeNum__cancel" @click="cancel" hover-class="seimin-btn-hover">
39
+          {{ operate.cancel || "" }}
40
+        </view>
41
+      </view>
42
+    </view>
43
+  </view>
44
+</template>
45
+
46
+<script>
47
+  import {
48
+    post
49
+  } from "../../http/http.js";
50
+  export default {
51
+    data() {
52
+      return {
53
+        imageValue: [], //图片列表
54
+        speNum: 0, //修改后的数量
55
+        reason: undefined, //修改原因
56
+        loading: false,
57
+        userData: null,
58
+        hosId: null,
59
+        timer: null,
60
+      };
61
+    },
62
+    watch: {
63
+      disjunctor(newValue) {
64
+        if (newValue && this.operate.know == "知道了") {
65
+          this.time = 5;
66
+          this.timer = setInterval(() => {
67
+            this.time--;
68
+            if (this.time <= 0) {
69
+              clearInterval(this.timer);
70
+              this.know();
71
+            }
72
+          }, 1000);
73
+        }
74
+      },
75
+    },
76
+    props: {
77
+      // 显示隐藏
78
+      disjunctor: {
79
+        type: Boolean,
80
+        default: false,
81
+      },
82
+      // 标题
83
+      title: {
84
+        type: String,
85
+        default: "提示",
86
+      },
87
+      // 操作按钮文字
88
+      operate: {
89
+        type: Object,
90
+        default: () => {
91
+          return {
92
+            ok: "确认",
93
+            cancel: "取消",
94
+          };
95
+        },
96
+      },
97
+      num: {
98
+        type: Number,
99
+        default: 0
100
+      }
101
+    },
102
+    methods: {
103
+      // 获取上传状态
104
+      selectFile(e) {
105
+        console.log('选择文件:', e)
106
+        this.imageValue = this.imageValue.concat(e.tempFiles);
107
+      },
108
+
109
+      // 移除
110
+      deleteFile(e) {
111
+        console.log('移除:', e);
112
+        this.imageValue = this.imageValue.filter(v=>v.uuid != e.tempFile.uuid);
113
+      },
114
+      // 确定
115
+      ok() {
116
+        this.$emit("ok", {
117
+          speNum: this.speNum,
118
+          reason: this.reason,
119
+          imageValue: this.imageValue,
120
+        });
121
+      },
122
+      // 取消
123
+      cancel() {
124
+        this.$emit("cancel");
125
+      },
126
+    },
127
+    created() {
128
+      this.speNum = this.num;
129
+      this.hosId = uni.getStorageSync('userData').user.currentHospital.id;
130
+    }
131
+  };
132
+</script>
133
+
134
+<style lang="less" scoped>
135
+  .changeSpeNum {
136
+    position: fixed;
137
+    left: 0;
138
+    right: 0;
139
+    top: 0;
140
+    bottom: 0;
141
+    background-color: rgba(0, 0, 0, 0.2);
142
+    z-index: 999;
143
+
144
+    .uni-list-cell {
145
+      width: 94%;
146
+      display: flex;
147
+      flex-direction: row;
148
+      justify-content: space-evenly;
149
+      align-items: center;
150
+      text-align: center;
151
+      margin-top: 32rpx;
152
+
153
+      .uni-list-cell-left {
154
+        flex: 2;
155
+        font-size: 32rpx;
156
+        color: #666;
157
+      }
158
+
159
+      .uni-list-cell-db {
160
+        padding: 16rpx 0;
161
+        flex: 5;
162
+      }
163
+
164
+      .uni-list-cell-db-text {
165
+        border: 1px solid #e5e9ed;
166
+        background-color: #fff;
167
+        flex: 5;
168
+        text-align: left;
169
+
170
+        textarea {
171
+          width: 100%;
172
+          box-sizing: border-box;
173
+          padding: 0 8rpx;
174
+          max-height: 150rpx;
175
+        }
176
+      }
177
+    }
178
+
179
+    .changeSpeNum__wrap {
180
+      width: 90vw;
181
+      position: absolute;
182
+      left: 50%;
183
+      top: 50%;
184
+      transform: translate(-50%, -50%);
185
+      background-color: #fff;
186
+      border-radius: 12rpx;
187
+      color: #666;
188
+
189
+      .changeSpeNum__header {
190
+        font-size: 36rpx;
191
+        color: #000;
192
+        height: 84rpx;
193
+        display: flex;
194
+        justify-content: center;
195
+        align-items: center;
196
+      }
197
+
198
+      .changeSpeNum__article {
199
+        width: 90%;
200
+        margin: 0 auto 25rpx;
201
+        padding: 48rpx 0;
202
+        background-color: rgb(249, 250, 251);
203
+        border: 2rpx solid rgb(229, 233, 237);
204
+        border-radius: 12rpx;
205
+        box-sizing: border-box;
206
+        display: flex;
207
+        flex-direction: column;
208
+        justify-content: center;
209
+        align-items: center;
210
+
211
+        &.p0 {
212
+          padding: 0;
213
+        }
214
+
215
+        .changeSpeNum__icon {
216
+          font-size: 138rpx;
217
+          margin-bottom: 32rpx;
218
+
219
+          &.changeSpeNum__icon--success {
220
+            color: rgb(52, 179, 73);
221
+          }
222
+
223
+          &.changeSpeNum__icon--warn {
224
+            color: rgb(245, 165, 35);
225
+          }
226
+
227
+          &.changeSpeNum__icon--error {
228
+            color: rgb(255, 58, 82);
229
+          }
230
+        }
231
+
232
+        .changeSpeNum__content {
233
+          font-size: 36rpx;
234
+        }
235
+
236
+        .changeSpeNum__info {
237
+          font-size: 32rpx;
238
+          color: rgb(102, 102, 102);
239
+        }
240
+
241
+        .specialCloseFlag {
242
+          width: 90%;
243
+          height: 100%;
244
+          padding: 16rpx;
245
+        }
246
+
247
+        .radio-wrap {
248
+          .radio-item {
249
+            margin-top: 16rpx;
250
+
251
+            /deep/ .uni-radio-input-checked {
252
+              background-color: #49b856 !important;
253
+              border-color: #49b856 !important;
254
+            }
255
+          }
256
+        }
257
+      }
258
+
259
+      .changeSpeNum__footer {
260
+        box-sizing: border-box;
261
+        height: 100rpx;
262
+        border-top: 2rpx solid rgb(229, 233, 237);
263
+        display: flex;
264
+        align-items: center;
265
+
266
+        view {
267
+          height: 100%;
268
+          display: flex;
269
+          align-items: center;
270
+          justify-content: center;
271
+          font-size: 36rpx;
272
+          color: rgb(102, 102, 102);
273
+          position: relative;
274
+
275
+          &:nth-of-type(2)::before {
276
+            content: "";
277
+            position: absolute;
278
+            left: 0;
279
+            bottom: 0;
280
+            width: 2rpx;
281
+            height: 87rpx;
282
+            background-color: rgb(229, 233, 237);
283
+          }
284
+        }
285
+
286
+        .changeSpeNum__ok {
287
+          flex: 1;
288
+          color: rgb(73, 184, 86);
289
+        }
290
+
291
+        .changeSpeNum__cancel {
292
+          flex: 1;
293
+        }
294
+
295
+        .changeSpeNum__know {
296
+          flex: 1;
297
+          color: rgb(73, 184, 86);
298
+        }
299
+      }
300
+    }
301
+  }
302
+</style>

+ 4 - 1
components/smallScreen/smallScreen.vue

@@ -206,8 +206,11 @@
206 206
               // id: data.id, //工单ID
207 207
               // deptCode: code, //二维码
208 208
               // dept: res.dept //科室名称
209
+              console.log(data,'工单')
210
+              let endDepts = data.endDepts.map(v=>v.id).toString();
211
+              console.log(endDepts,'smallScreen');
209 212
               uni.navigateTo({
210
-                url: `../../pages/scanning_code/scanning_code?type=${data.taskType.associationType.value}&type1=${res.type}&id=${data.id}&deptCode=${code}&dept=${res.dept}&accountObj=${encodeURIComponent(JSON.stringify(accountObj))}&deptId=${res.deptId}`,
213
+                url: `../../pages/scanning_code/scanning_code?type=${data.taskType.associationType.value}&type1=${res.type}&id=${data.id}&deptCode=${code}&dept=${res.dept}&accountObj=${encodeURIComponent(JSON.stringify(accountObj))}&deptId=${res.deptId}&endDepts=${endDepts}`,
211 214
               });
212 215
             } else {
213 216
               uni.navigateTo({

+ 224 - 0
components/uni-file-picker/choose-and-upload-file.js

@@ -0,0 +1,224 @@
1
+'use strict';
2
+
3
+const ERR_MSG_OK = 'chooseAndUploadFile:ok';
4
+const ERR_MSG_FAIL = 'chooseAndUploadFile:fail';
5
+
6
+function chooseImage(opts) {
7
+	const {
8
+		count,
9
+		sizeType = ['original', 'compressed'],
10
+		sourceType = ['album', 'camera'],
11
+		extension
12
+	} = opts
13
+	return new Promise((resolve, reject) => {
14
+		uni.chooseImage({
15
+			count,
16
+			sizeType,
17
+			sourceType,
18
+			extension,
19
+			success(res) {
20
+				resolve(normalizeChooseAndUploadFileRes(res, 'image'));
21
+			},
22
+			fail(res) {
23
+				reject({
24
+					errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
25
+				});
26
+			},
27
+		});
28
+	});
29
+}
30
+
31
+function chooseVideo(opts) {
32
+	const {
33
+		camera,
34
+		compressed,
35
+		maxDuration,
36
+		sourceType = ['album', 'camera'],
37
+		extension
38
+	} = opts;
39
+	return new Promise((resolve, reject) => {
40
+		uni.chooseVideo({
41
+			camera,
42
+			compressed,
43
+			maxDuration,
44
+			sourceType,
45
+			extension,
46
+			success(res) {
47
+				const {
48
+					tempFilePath,
49
+					duration,
50
+					size,
51
+					height,
52
+					width
53
+				} = res;
54
+				resolve(normalizeChooseAndUploadFileRes({
55
+					errMsg: 'chooseVideo:ok',
56
+					tempFilePaths: [tempFilePath],
57
+					tempFiles: [
58
+					{
59
+						name: (res.tempFile && res.tempFile.name) || '',
60
+						path: tempFilePath,
61
+						size,
62
+						type: (res.tempFile && res.tempFile.type) || '',
63
+						width,
64
+						height,
65
+						duration,
66
+						fileType: 'video',
67
+						cloudPath: '',
68
+					}, ],
69
+				}, 'video'));
70
+			},
71
+			fail(res) {
72
+				reject({
73
+					errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL),
74
+				});
75
+			},
76
+		});
77
+	});
78
+}
79
+
80
+function chooseAll(opts) {
81
+	const {
82
+		count,
83
+		extension
84
+	} = opts;
85
+	return new Promise((resolve, reject) => {
86
+		let chooseFile = uni.chooseFile;
87
+		if (typeof wx !== 'undefined' &&
88
+			typeof wx.chooseMessageFile === 'function') {
89
+			chooseFile = wx.chooseMessageFile;
90
+		}
91
+		if (typeof chooseFile !== 'function') {
92
+			return reject({
93
+				errMsg: ERR_MSG_FAIL + ' 请指定 type 类型,该平台仅支持选择 image 或 video。',
94
+			});
95
+		}
96
+		chooseFile({
97
+			type: 'all',
98
+			count,
99
+			extension,
100
+			success(res) {
101
+				resolve(normalizeChooseAndUploadFileRes(res));
102
+			},
103
+			fail(res) {
104
+				reject({
105
+					errMsg: res.errMsg.replace('chooseFile:fail', ERR_MSG_FAIL),
106
+				});
107
+			},
108
+		});
109
+	});
110
+}
111
+
112
+function normalizeChooseAndUploadFileRes(res, fileType) {
113
+	res.tempFiles.forEach((item, index) => {
114
+		if (!item.name) {
115
+			item.name = item.path.substring(item.path.lastIndexOf('/') + 1);
116
+		}
117
+		if (fileType) {
118
+			item.fileType = fileType;
119
+		}
120
+		item.cloudPath =
121
+			Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.'));
122
+	});
123
+	if (!res.tempFilePaths) {
124
+		res.tempFilePaths = res.tempFiles.map((file) => file.path);
125
+	}
126
+	return res;
127
+}
128
+
129
+function uploadCloudFiles(files, max = 5, onUploadProgress) {
130
+	files = JSON.parse(JSON.stringify(files))
131
+	const len = files.length
132
+	let count = 0
133
+	let self = this
134
+	return new Promise(resolve => {
135
+		while (count < max) {
136
+			next()
137
+		}
138
+
139
+		function next() {
140
+			let cur = count++
141
+			if (cur >= len) {
142
+				!files.find(item => !item.url && !item.errMsg) && resolve(files)
143
+				return
144
+			}
145
+			const fileItem = files[cur]
146
+			const index = self.files.findIndex(v => v.uuid === fileItem.uuid)
147
+			fileItem.url = ''
148
+			delete fileItem.errMsg
149
+
150
+			uniCloud
151
+				.uploadFile({
152
+					filePath: fileItem.path,
153
+					cloudPath: fileItem.cloudPath,
154
+					fileType: fileItem.fileType,
155
+					onUploadProgress: res => {
156
+						res.index = index
157
+						onUploadProgress && onUploadProgress(res)
158
+					}
159
+				})
160
+				.then(res => {
161
+					fileItem.url = res.fileID
162
+					fileItem.index = index
163
+					if (cur < len) {
164
+						next()
165
+					}
166
+				})
167
+				.catch(res => {
168
+					fileItem.errMsg = res.errMsg || res.message
169
+					fileItem.index = index
170
+					if (cur < len) {
171
+						next()
172
+					}
173
+				})
174
+		}
175
+	})
176
+}
177
+
178
+
179
+
180
+
181
+
182
+function uploadFiles(choosePromise, {
183
+	onChooseFile,
184
+	onUploadProgress
185
+}) {
186
+	return choosePromise
187
+		.then((res) => {
188
+			if (onChooseFile) {
189
+				const customChooseRes = onChooseFile(res);
190
+				if (typeof customChooseRes !== 'undefined') {
191
+					return Promise.resolve(customChooseRes).then((chooseRes) => typeof chooseRes === 'undefined' ?
192
+						res : chooseRes);
193
+				}
194
+			}
195
+			return res;
196
+		})
197
+		.then((res) => {
198
+			if (res === false) {
199
+				return {
200
+					errMsg: ERR_MSG_OK,
201
+					tempFilePaths: [],
202
+					tempFiles: [],
203
+				};
204
+			}
205
+			return res
206
+		})
207
+}
208
+
209
+function chooseAndUploadFile(opts = {
210
+	type: 'all'
211
+}) {
212
+	if (opts.type === 'image') {
213
+		return uploadFiles(chooseImage(opts), opts);
214
+	}
215
+	else if (opts.type === 'video') {
216
+		return uploadFiles(chooseVideo(opts), opts);
217
+	}
218
+	return uploadFiles(chooseAll(opts), opts);
219
+}
220
+
221
+export {
222
+	chooseAndUploadFile,
223
+	uploadCloudFiles
224
+};

+ 656 - 0
components/uni-file-picker/uni-file-picker.vue

@@ -0,0 +1,656 @@
1
+<template>
2
+	<view class="uni-file-picker">
3
+		<view v-if="title" class="uni-file-picker__header">
4
+			<text class="file-title">{{ title }}</text>
5
+			<text class="file-count">{{ filesList.length }}/{{ limitLength }}</text>
6
+		</view>
7
+		<upload-image v-if="fileMediatype === 'image' && showType === 'grid'" :readonly="readonly"
8
+			:image-styles="imageStyles" :files-list="filesList" :limit="limitLength" :disablePreview="disablePreview"
9
+			:delIcon="delIcon" @uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
10
+			<slot>
11
+				<view class="is-add">
12
+					<view class="icon-add"></view>
13
+					<view class="icon-add rotate"></view>
14
+				</view>
15
+			</slot>
16
+		</upload-image>
17
+		<upload-file v-if="fileMediatype !== 'image' || showType !== 'grid'" :readonly="readonly"
18
+			:list-styles="listStyles" :files-list="filesList" :showType="showType" :delIcon="delIcon"
19
+			@uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
20
+			<slot><button type="primary" size="mini">选择文件</button></slot>
21
+		</upload-file>
22
+	</view>
23
+</template>
24
+
25
+<script>
26
+	import {
27
+		chooseAndUploadFile,
28
+		uploadCloudFiles
29
+	} from './choose-and-upload-file.js'
30
+	import {
31
+		get_file_ext,
32
+		get_extname,
33
+		get_files_and_is_max,
34
+		get_file_info,
35
+		get_file_data
36
+	} from './utils.js'
37
+	import uploadImage from './upload-image.vue'
38
+	import uploadFile from './upload-file.vue'
39
+	let fileInput = null
40
+	/**
41
+	 * FilePicker 文件选择上传
42
+	 * @description 文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
43
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=4079
44
+	 * @property {Object|Array}	value	组件数据,通常用来回显 ,类型由return-type属性决定
45
+	 * @property {Boolean}	disabled = [true|false]	组件禁用
46
+	 * 	@value true 	禁用
47
+	 * 	@value false 	取消禁用
48
+	 * @property {Boolean}	readonly = [true|false]	组件只读,不可选择,不显示进度,不显示删除按钮
49
+	 * 	@value true 	只读
50
+	 * 	@value false 	取消只读
51
+	 * @property {String}	return-type = [array|object]	限制 value 格式,当为 object 时 ,组件只能单选,且会覆盖
52
+	 * 	@value array	规定 value 属性的类型为数组
53
+	 * 	@value object	规定 value 属性的类型为对象
54
+	 * @property {Boolean}	disable-preview = [true|false]	禁用图片预览,仅 mode:grid 时生效
55
+	 * 	@value true 	禁用图片预览
56
+	 * 	@value false 	取消禁用图片预览
57
+	 * @property {Boolean}	del-icon = [true|false]	是否显示删除按钮
58
+	 * 	@value true 	显示删除按钮
59
+	 * 	@value false 	不显示删除按钮
60
+	 * @property {Boolean}	auto-upload = [true|false]	是否自动上传,值为true则只触发@select,可自行上传
61
+	 * 	@value true 	自动上传
62
+	 * 	@value false 	取消自动上传
63
+	 * @property {Number|String}	limit	最大选择个数 ,h5 会自动忽略多选的部分
64
+	 * @property {String}	title	组件标题,右侧显示上传计数
65
+	 * @property {String}	mode = [list|grid]	选择文件后的文件列表样式
66
+	 * 	@value list 	列表显示
67
+	 * 	@value grid 	宫格显示
68
+	 * @property {String}	file-mediatype = [image|video|all]	选择文件类型
69
+	 * 	@value image	只选择图片
70
+	 * 	@value video	只选择视频
71
+	 * 	@value all		选择所有文件
72
+	 * @property {Array}	file-extname	选择文件后缀,根据 file-mediatype 属性而不同
73
+	 * @property {Object}	list-style	mode:list 时的样式
74
+	 * @property {Object}	image-styles	选择文件后缀,根据 file-mediatype 属性而不同
75
+	 * @event {Function} select 	选择文件后触发
76
+	 * @event {Function} progress 文件上传时触发
77
+	 * @event {Function} success 	上传成功触发
78
+	 * @event {Function} fail 		上传失败触发
79
+	 * @event {Function} delete 	文件从列表移除时触发
80
+	 */
81
+	export default {
82
+		name: 'uniFilePicker',
83
+		components: {
84
+			uploadImage,
85
+			uploadFile
86
+		},
87
+		options: {
88
+			virtualHost: true
89
+		},
90
+		emits: ['select', 'success', 'fail', 'progress', 'delete', 'update:modelValue', 'input'],
91
+		props: {
92
+			// #ifdef VUE3
93
+			modelValue: {
94
+				type: [Array, Object],
95
+				default () {
96
+					return []
97
+				}
98
+			},
99
+			// #endif
100
+
101
+			// #ifndef VUE3
102
+			value: {
103
+				type: [Array, Object],
104
+				default () {
105
+					return []
106
+				}
107
+			},
108
+			// #endif
109
+
110
+			disabled: {
111
+				type: Boolean,
112
+				default: false
113
+			},
114
+			disablePreview: {
115
+				type: Boolean,
116
+				default: false
117
+			},
118
+			delIcon: {
119
+				type: Boolean,
120
+				default: true
121
+			},
122
+			// 自动上传
123
+			autoUpload: {
124
+				type: Boolean,
125
+				default: true
126
+			},
127
+			// 最大选择个数 ,h5只能限制单选或是多选
128
+			limit: {
129
+				type: [Number, String],
130
+				default: 9
131
+			},
132
+			// 列表样式 grid | list | list-card
133
+			mode: {
134
+				type: String,
135
+				default: 'grid'
136
+			},
137
+			// 选择文件类型  image/video/all
138
+			fileMediatype: {
139
+				type: String,
140
+				default: 'image'
141
+			},
142
+			// 文件类型筛选
143
+			fileExtname: {
144
+				type: [Array, String],
145
+				default () {
146
+					return []
147
+				}
148
+			},
149
+			title: {
150
+				type: String,
151
+				default: ''
152
+			},
153
+			listStyles: {
154
+				type: Object,
155
+				default () {
156
+					return {
157
+						// 是否显示边框
158
+						border: true,
159
+						// 是否显示分隔线
160
+						dividline: true,
161
+						// 线条样式
162
+						borderStyle: {}
163
+					}
164
+				}
165
+			},
166
+			imageStyles: {
167
+				type: Object,
168
+				default () {
169
+					return {
170
+						width: 'auto',
171
+						height: 'auto'
172
+					}
173
+				}
174
+			},
175
+			readonly: {
176
+				type: Boolean,
177
+				default: false
178
+			},
179
+			returnType: {
180
+				type: String,
181
+				default: 'array'
182
+			},
183
+			sizeType: {
184
+				type: Array,
185
+				default () {
186
+					return ['original', 'compressed']
187
+				}
188
+			}
189
+		},
190
+		data() {
191
+			return {
192
+				files: [],
193
+				localValue: []
194
+			}
195
+		},
196
+		watch: {
197
+			// #ifndef VUE3
198
+			value: {
199
+				handler(newVal, oldVal) {
200
+					this.setValue(newVal, oldVal)
201
+				},
202
+				immediate: true
203
+			},
204
+			// #endif
205
+			// #ifdef VUE3
206
+			modelValue: {
207
+				handler(newVal, oldVal) {
208
+					this.setValue(newVal, oldVal)
209
+				},
210
+				immediate: true
211
+			},
212
+			// #endif
213
+		},
214
+		computed: {
215
+			filesList() {
216
+				let files = []
217
+				this.files.forEach(v => {
218
+					files.push(v)
219
+				})
220
+				return files
221
+			},
222
+			showType() {
223
+				if (this.fileMediatype === 'image') {
224
+					return this.mode
225
+				}
226
+				return 'list'
227
+			},
228
+			limitLength() {
229
+				if (this.returnType === 'object') {
230
+					return 1
231
+				}
232
+				if (!this.limit) {
233
+					return 1
234
+				}
235
+				if (this.limit >= 9) {
236
+					return 9
237
+				}
238
+				return this.limit
239
+			}
240
+		},
241
+		created() {
242
+			// TODO 兼容不开通服务空间的情况
243
+			if (!(uniCloud.config && uniCloud.config.provider)) {
244
+				this.noSpace = true
245
+				uniCloud.chooseAndUploadFile = chooseAndUploadFile
246
+			}
247
+			this.form = this.getForm('uniForms')
248
+			this.formItem = this.getForm('uniFormsItem')
249
+			if (this.form && this.formItem) {
250
+				if (this.formItem.name) {
251
+					this.rename = this.formItem.name
252
+					this.form.inputChildrens.push(this)
253
+				}
254
+			}
255
+		},
256
+		methods: {
257
+			/**
258
+			 * 公开用户使用,清空文件
259
+			 * @param {Object} index
260
+			 */
261
+			clearFiles(index) {
262
+				if (index !== 0 && !index) {
263
+					this.files = []
264
+					this.$nextTick(() => {
265
+						this.setEmit()
266
+					})
267
+				} else {
268
+					this.files.splice(index, 1)
269
+				}
270
+				this.$nextTick(() => {
271
+					this.setEmit()
272
+				})
273
+			},
274
+			/**
275
+			 * 公开用户使用,继续上传
276
+			 */
277
+			upload() {
278
+				let files = []
279
+				this.files.forEach((v, index) => {
280
+					if (v.status === 'ready' || v.status === 'error') {
281
+						files.push(Object.assign({}, v))
282
+					}
283
+				})
284
+				return this.uploadFiles(files)
285
+			},
286
+			async setValue(newVal, oldVal) {
287
+				const newData =  async (v) => {
288
+					const reg = /cloud:\/\/([\w.]+\/?)\S*/
289
+					let url = ''
290
+					if(v.fileID){
291
+						url = v.fileID
292
+					}else{
293
+						url = v.url
294
+					}
295
+					if (reg.test(url)) {
296
+						v.fileID = url
297
+						v.url = await this.getTempFileURL(url)
298
+					}
299
+					if(v.url) v.path = v.url
300
+					return v
301
+				}
302
+				if (this.returnType === 'object') {
303
+					if (newVal) {
304
+						await newData(newVal)
305
+					} else {
306
+						newVal = {}
307
+					}
308
+				} else {
309
+					if (!newVal) newVal = []
310
+					for(let i =0 ;i < newVal.length ;i++){
311
+						let v = newVal[i]
312
+						await newData(v)
313
+					}
314
+				}
315
+				this.localValue = newVal
316
+				if (this.form && this.formItem &&!this.is_reset) {
317
+					this.is_reset = false
318
+					this.formItem.setValue(this.localValue)
319
+				}
320
+				let filesData = Object.keys(newVal).length > 0 ? newVal : [];
321
+				this.files = [].concat(filesData)
322
+			},
323
+
324
+			/**
325
+			 * 选择文件
326
+			 */
327
+			choose() {
328
+
329
+				if (this.disabled) return
330
+				if (this.files.length >= Number(this.limitLength) && this.showType !== 'grid' && this.returnType ===
331
+					'array') {
332
+					uni.showToast({
333
+						title: `您最多选择 ${this.limitLength} 个文件`,
334
+						icon: 'none'
335
+					})
336
+					return
337
+				}
338
+				this.chooseFiles()
339
+			},
340
+
341
+			/**
342
+			 * 选择文件并上传
343
+			 */
344
+			chooseFiles() {
345
+				const _extname = get_extname(this.fileExtname)
346
+				// 获取后缀
347
+				uniCloud
348
+					.chooseAndUploadFile({
349
+						type: this.fileMediatype,
350
+						compressed: false,
351
+						sizeType: this.sizeType,
352
+						// TODO 如果为空,video 有问题
353
+						extension: _extname.length > 0 ? _extname : undefined,
354
+						count: this.limitLength - this.files.length, //默认9
355
+						onChooseFile: this.chooseFileCallback,
356
+						onUploadProgress: progressEvent => {
357
+							this.setProgress(progressEvent, progressEvent.index)
358
+						}
359
+					})
360
+					.then(result => {
361
+						this.setSuccessAndError(result.tempFiles)
362
+					})
363
+					.catch(err => {
364
+						console.log('选择失败', err)
365
+					})
366
+			},
367
+
368
+			/**
369
+			 * 选择文件回调
370
+			 * @param {Object} res
371
+			 */
372
+			async chooseFileCallback(res) {
373
+				const _extname = get_extname(this.fileExtname)
374
+				const is_one = (Number(this.limitLength) === 1 &&
375
+						this.disablePreview &&
376
+						!this.disabled) ||
377
+					this.returnType === 'object'
378
+				// 如果这有一个文件 ,需要清空本地缓存数据
379
+				if (is_one) {
380
+					this.files = []
381
+				}
382
+
383
+				let {
384
+					filePaths,
385
+					files
386
+				} = get_files_and_is_max(res, _extname)
387
+				if (!(_extname && _extname.length > 0)) {
388
+					filePaths = res.tempFilePaths
389
+					files = res.tempFiles
390
+				}
391
+
392
+				let currentData = []
393
+				for (let i = 0; i < files.length; i++) {
394
+					if (this.limitLength - this.files.length <= 0) break
395
+					files[i].uuid = Date.now()
396
+					let filedata = await get_file_data(files[i], this.fileMediatype)
397
+					filedata.progress = 0
398
+					filedata.status = 'ready'
399
+					this.files.push(filedata)
400
+					currentData.push({
401
+						...filedata,
402
+						file: files[i]
403
+					})
404
+				}
405
+				this.$emit('select', {
406
+					tempFiles: currentData,
407
+					tempFilePaths: filePaths
408
+				})
409
+				res.tempFiles = files
410
+				// 停止自动上传
411
+				if (!this.autoUpload || this.noSpace) {
412
+					res.tempFiles = []
413
+				}
414
+			},
415
+
416
+			/**
417
+			 * 批传
418
+			 * @param {Object} e
419
+			 */
420
+			uploadFiles(files) {
421
+				files = [].concat(files)
422
+				return uploadCloudFiles.call(this, files, 5, res => {
423
+						this.setProgress(res, res.index, true)
424
+					})
425
+					.then(result => {
426
+						this.setSuccessAndError(result)
427
+						return result;
428
+					})
429
+					.catch(err => {
430
+						console.log(err)
431
+					})
432
+			},
433
+
434
+			/**
435
+			 * 成功或失败
436
+			 */
437
+			async setSuccessAndError(res, fn) {
438
+				let successData = []
439
+				let errorData = []
440
+				let tempFilePath = []
441
+				let errorTempFilePath = []
442
+				for (let i = 0; i < res.length; i++) {
443
+					const item = res[i]
444
+					const index = item.uuid ? this.files.findIndex(p => p.uuid === item.uuid) : item.index
445
+
446
+					if (index === -1 || !this.files) break
447
+					if (item.errMsg === 'request:fail') {
448
+						this.files[index].url = item.path
449
+						this.files[index].status = 'error'
450
+						this.files[index].errMsg = item.errMsg
451
+						// this.files[index].progress = -1
452
+						errorData.push(this.files[index])
453
+						errorTempFilePath.push(this.files[index].url)
454
+					} else {
455
+						this.files[index].errMsg = ''
456
+						this.files[index].fileID = item.url
457
+						const reg = /cloud:\/\/([\w.]+\/?)\S*/
458
+						if (reg.test(item.url)) {
459
+							this.files[index].url = await this.getTempFileURL(item.url)
460
+						}else{
461
+							this.files[index].url = item.url
462
+						}
463
+
464
+						this.files[index].status = 'success'
465
+						this.files[index].progress += 1
466
+						successData.push(this.files[index])
467
+						tempFilePath.push(this.files[index].fileID)
468
+					}
469
+				}
470
+
471
+				if (successData.length > 0) {
472
+					this.setEmit()
473
+					// 状态改变返回
474
+					this.$emit('success', {
475
+						tempFiles: this.backObject(successData),
476
+						tempFilePaths: tempFilePath
477
+					})
478
+				}
479
+
480
+				if (errorData.length > 0) {
481
+					this.$emit('fail', {
482
+						tempFiles: this.backObject(errorData),
483
+						tempFilePaths: errorTempFilePath
484
+					})
485
+				}
486
+			},
487
+
488
+			/**
489
+			 * 获取进度
490
+			 * @param {Object} progressEvent
491
+			 * @param {Object} index
492
+			 * @param {Object} type
493
+			 */
494
+			setProgress(progressEvent, index, type) {
495
+				const fileLenth = this.files.length
496
+				const percentNum = (index / fileLenth) * 100
497
+				const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
498
+				let idx = index
499
+				if (!type) {
500
+					idx = this.files.findIndex(p => p.uuid === progressEvent.tempFile.uuid)
501
+				}
502
+				if (idx === -1 || !this.files[idx]) return
503
+				// fix by mehaotian 100 就会消失,-1 是为了让进度条消失
504
+				this.files[idx].progress = percentCompleted - 1
505
+				// 上传中
506
+				this.$emit('progress', {
507
+					index: idx,
508
+					progress: parseInt(percentCompleted),
509
+					tempFile: this.files[idx]
510
+				})
511
+			},
512
+
513
+			/**
514
+			 * 删除文件
515
+			 * @param {Object} index
516
+			 */
517
+			delFile(index) {
518
+				this.$emit('delete', {
519
+					tempFile: this.files[index],
520
+					tempFilePath: this.files[index].url
521
+				})
522
+				this.files.splice(index, 1)
523
+				this.$nextTick(() => {
524
+					this.setEmit()
525
+				})
526
+			},
527
+
528
+			/**
529
+			 * 获取文件名和后缀
530
+			 * @param {Object} name
531
+			 */
532
+			getFileExt(name) {
533
+				const last_len = name.lastIndexOf('.')
534
+				const len = name.length
535
+				return {
536
+					name: name.substring(0, last_len),
537
+					ext: name.substring(last_len + 1, len)
538
+				}
539
+			},
540
+
541
+			/**
542
+			 * 处理返回事件
543
+			 */
544
+			setEmit() {
545
+				let data = []
546
+				if (this.returnType === 'object') {
547
+					data = this.backObject(this.files)[0]
548
+					this.localValue = data?data:null
549
+				} else {
550
+					data = this.backObject(this.files)
551
+					if (!this.localValue) {
552
+						this.localValue = []
553
+					}
554
+					this.localValue = [...data]
555
+				}
556
+				// #ifdef VUE3
557
+				this.$emit('update:modelValue', this.localValue)
558
+				// #endif
559
+				// #ifndef VUE3
560
+				this.$emit('input', this.localValue)
561
+				// #endif
562
+			},
563
+
564
+			/**
565
+			 * 处理返回参数
566
+			 * @param {Object} files
567
+			 */
568
+			backObject(files) {
569
+				let newFilesData = []
570
+				files.forEach(v => {
571
+					newFilesData.push({
572
+						extname: v.extname,
573
+						fileType: v.fileType,
574
+						image: v.image,
575
+						name: v.name,
576
+						path: v.path,
577
+						size: v.size,
578
+						fileID:v.fileID,
579
+						url: v.url
580
+					})
581
+				})
582
+				return newFilesData
583
+			},
584
+			async getTempFileURL(fileList) {
585
+				fileList = {
586
+					fileList: [].concat(fileList)
587
+				}
588
+				const urls = await uniCloud.getTempFileURL(fileList)
589
+				return urls.fileList[0].tempFileURL || ''
590
+			},
591
+			/**
592
+			 * 获取父元素实例
593
+			 */
594
+			getForm(name = 'uniForms') {
595
+				let parent = this.$parent;
596
+				let parentName = parent.$options.name;
597
+				while (parentName !== name) {
598
+					parent = parent.$parent;
599
+					if (!parent) return false;
600
+					parentName = parent.$options.name;
601
+				}
602
+				return parent;
603
+			}
604
+		}
605
+	}
606
+</script>
607
+
608
+<style>
609
+	.uni-file-picker {
610
+		/* #ifndef APP-NVUE */
611
+		box-sizing: border-box;
612
+		overflow: hidden;
613
+		width: 100%;
614
+		/* #endif */
615
+		flex: 1;
616
+	}
617
+
618
+	.uni-file-picker__header {
619
+		padding-top: 5px;
620
+		padding-bottom: 10px;
621
+		/* #ifndef APP-NVUE */
622
+		display: flex;
623
+		/* #endif */
624
+		justify-content: space-between;
625
+	}
626
+
627
+	.file-title {
628
+		font-size: 14px;
629
+		color: #333;
630
+	}
631
+
632
+	.file-count {
633
+		font-size: 14px;
634
+		color: #999;
635
+	}
636
+
637
+	.is-add {
638
+		/* #ifndef APP-NVUE */
639
+		display: flex;
640
+		/* #endif */
641
+		align-items: center;
642
+		justify-content: center;
643
+	}
644
+
645
+	.icon-add {
646
+		width: 50px;
647
+		height: 5px;
648
+		background-color: #f1f1f1;
649
+		border-radius: 2px;
650
+	}
651
+
652
+	.rotate {
653
+		position: absolute;
654
+		transform: rotate(90deg);
655
+	}
656
+</style>

+ 325 - 0
components/uni-file-picker/upload-file.vue

@@ -0,0 +1,325 @@
1
+<template>
2
+	<view class="uni-file-picker__files">
3
+		<view v-if="!readonly" class="files-button" @click="choose">
4
+			<slot></slot>
5
+		</view>
6
+		<!-- :class="{'is-text-box':showType === 'list'}" -->
7
+		<view v-if="list.length > 0" class="uni-file-picker__lists is-text-box" :style="borderStyle">
8
+			<!-- ,'is-list-card':showType === 'list-card' -->
9
+
10
+			<view class="uni-file-picker__lists-box" v-for="(item ,index) in list" :key="index" :class="{
11
+				'files-border':index !== 0 && styles.dividline}"
12
+			 :style="index !== 0 && styles.dividline &&borderLineStyle">
13
+				<view class="uni-file-picker__item">
14
+					<!-- :class="{'is-text-image':showType === 'list'}" -->
15
+					<!-- 	<view class="files__image is-text-image">
16
+						<image class="header-image" :src="item.logo" mode="aspectFit"></image>
17
+					</view> -->
18
+					<view class="files__name">{{item.name}}</view>
19
+					<view v-if="delIcon&&!readonly" class="icon-del-box icon-files" @click="delFile(index)">
20
+						<view class="icon-del icon-files"></view>
21
+						<view class="icon-del rotate"></view>
22
+					</view>
23
+				</view>
24
+				<view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress">
25
+					<progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4"
26
+					 :backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" />
27
+				</view>
28
+				<view v-if="item.status === 'error'" class="file-picker__mask" @click.stop="uploadFiles(item,index)">
29
+					点击重试
30
+				</view>
31
+			</view>
32
+
33
+		</view>
34
+	</view>
35
+</template>
36
+
37
+<script>
38
+	export default {
39
+		name: "uploadFile",
40
+		emits:['uploadFiles','choose','delFile'],
41
+		props: {
42
+			filesList: {
43
+				type: Array,
44
+				default () {
45
+					return []
46
+				}
47
+			},
48
+			delIcon: {
49
+				type: Boolean,
50
+				default: true
51
+			},
52
+			limit: {
53
+				type: [Number, String],
54
+				default: 9
55
+			},
56
+			showType: {
57
+				type: String,
58
+				default: ''
59
+			},
60
+			listStyles: {
61
+				type: Object,
62
+				default () {
63
+					return {
64
+						// 是否显示边框
65
+						border: true,
66
+						// 是否显示分隔线
67
+						dividline: true,
68
+						// 线条样式
69
+						borderStyle: {}
70
+					}
71
+				}
72
+			},
73
+			readonly:{
74
+				type:Boolean,
75
+				default:false
76
+			}
77
+		},
78
+		computed: {
79
+			list() {
80
+				let files = []
81
+				this.filesList.forEach(v => {
82
+					files.push(v)
83
+				})
84
+				return files
85
+			},
86
+			styles() {
87
+				let styles = {
88
+					border: true,
89
+					dividline: true,
90
+					'border-style': {}
91
+				}
92
+				return Object.assign(styles, this.listStyles)
93
+			},
94
+			borderStyle() {
95
+				let {
96
+					borderStyle,
97
+					border
98
+				} = this.styles
99
+				let obj = {}
100
+				if (!border) {
101
+					obj.border = 'none'
102
+				} else {
103
+					let width = (borderStyle && borderStyle.width) || 1
104
+					width = this.value2px(width)
105
+					let radius = (borderStyle && borderStyle.radius) || 5
106
+					radius = this.value2px(radius)
107
+					obj = {
108
+						'border-width': width,
109
+						'border-style': (borderStyle && borderStyle.style) || 'solid',
110
+						'border-color': (borderStyle && borderStyle.color) || '#eee',
111
+						'border-radius': radius
112
+					}
113
+				}
114
+				let classles = ''
115
+				for (let i in obj) {
116
+					classles += `${i}:${obj[i]};`
117
+				}
118
+				return classles
119
+			},
120
+			borderLineStyle() {
121
+				let obj = {}
122
+				let {
123
+					borderStyle
124
+				} = this.styles
125
+				if (borderStyle && borderStyle.color) {
126
+					obj['border-color'] = borderStyle.color
127
+				}
128
+				if (borderStyle && borderStyle.width) {
129
+					let width = borderStyle && borderStyle.width || 1
130
+					let style = borderStyle && borderStyle.style || 0
131
+					if (typeof width === 'number') {
132
+						width += 'px'
133
+					} else {
134
+						width = width.indexOf('px') ? width : width + 'px'
135
+					}
136
+					obj['border-width'] = width
137
+
138
+					if (typeof style === 'number') {
139
+						style += 'px'
140
+					} else {
141
+						style = style.indexOf('px') ? style : style + 'px'
142
+					}
143
+					obj['border-top-style'] = style
144
+				}
145
+				let classles = ''
146
+				for (let i in obj) {
147
+					classles += `${i}:${obj[i]};`
148
+				}
149
+				return classles
150
+			}
151
+		},
152
+
153
+		methods: {
154
+			uploadFiles(item, index) {
155
+				this.$emit("uploadFiles", {
156
+					item,
157
+					index
158
+				})
159
+			},
160
+			choose() {
161
+				this.$emit("choose")
162
+			},
163
+			delFile(index) {
164
+				this.$emit('delFile', index)
165
+			},
166
+			value2px(value) {
167
+				if (typeof value === 'number') {
168
+					value += 'px'
169
+				} else {
170
+					value = value.indexOf('px') !== -1 ? value : value + 'px'
171
+				}
172
+				return value
173
+			}
174
+		}
175
+	}
176
+</script>
177
+
178
+<style lang="scss">
179
+	.uni-file-picker__files {
180
+		/* #ifndef APP-NVUE */
181
+		display: flex;
182
+		/* #endif */
183
+		flex-direction: column;
184
+		justify-content: flex-start;
185
+	}
186
+
187
+	.files-button {
188
+		// border: 1px red solid;
189
+	}
190
+
191
+	.uni-file-picker__lists {
192
+		position: relative;
193
+		margin-top: 5px;
194
+		overflow: hidden;
195
+	}
196
+
197
+	.file-picker__mask {
198
+		/* #ifndef APP-NVUE */
199
+		display: flex;
200
+		/* #endif */
201
+		justify-content: center;
202
+		align-items: center;
203
+		position: absolute;
204
+		right: 0;
205
+		top: 0;
206
+		bottom: 0;
207
+		left: 0;
208
+		color: #fff;
209
+		font-size: 14px;
210
+		background-color: rgba(0, 0, 0, 0.4);
211
+	}
212
+
213
+	.uni-file-picker__lists-box {
214
+		position: relative;
215
+	}
216
+
217
+	.uni-file-picker__item {
218
+		/* #ifndef APP-NVUE */
219
+		display: flex;
220
+		/* #endif */
221
+		align-items: center;
222
+		padding: 8px 10px;
223
+		padding-right: 5px;
224
+		padding-left: 10px;
225
+	}
226
+
227
+	.files-border {
228
+		border-top: 1px #eee solid;
229
+	}
230
+
231
+	.files__name {
232
+		flex: 1;
233
+		font-size: 14px;
234
+		color: #666;
235
+		margin-right: 25px;
236
+		/* #ifndef APP-NVUE */
237
+		word-break: break-all;
238
+		word-wrap: break-word;
239
+		/* #endif */
240
+	}
241
+
242
+	.icon-files {
243
+		/* #ifndef APP-NVUE */
244
+		position: static;
245
+		background-color: initial;
246
+		/* #endif */
247
+	}
248
+
249
+	// .icon-files .icon-del {
250
+	// 	background-color: #333;
251
+	// 	width: 12px;
252
+	// 	height: 1px;
253
+	// }
254
+
255
+
256
+	.is-list-card {
257
+		border: 1px #eee solid;
258
+		margin-bottom: 5px;
259
+		border-radius: 5px;
260
+		box-shadow: 0 0 2px 0px rgba(0, 0, 0, 0.1);
261
+		padding: 5px;
262
+	}
263
+
264
+	.files__image {
265
+		width: 40px;
266
+		height: 40px;
267
+		margin-right: 10px;
268
+	}
269
+
270
+	.header-image {
271
+		width: 100%;
272
+		height: 100%;
273
+	}
274
+
275
+	.is-text-box {
276
+		border: 1px #eee solid;
277
+		border-radius: 5px;
278
+	}
279
+
280
+	.is-text-image {
281
+		width: 25px;
282
+		height: 25px;
283
+		margin-left: 5px;
284
+	}
285
+
286
+	.rotate {
287
+		position: absolute;
288
+		transform: rotate(90deg);
289
+	}
290
+
291
+	.icon-del-box {
292
+		/* #ifndef APP-NVUE */
293
+		display: flex;
294
+		margin: auto 0;
295
+		/* #endif */
296
+		align-items: center;
297
+		justify-content: center;
298
+		position: absolute;
299
+		top: 0px;
300
+		bottom: 0;
301
+		right: 5px;
302
+		height: 26px;
303
+		width: 26px;
304
+		// border-radius: 50%;
305
+		// background-color: rgba(0, 0, 0, 0.5);
306
+		z-index: 2;
307
+		transform: rotate(-45deg);
308
+	}
309
+
310
+	.icon-del {
311
+		width: 15px;
312
+		height: 1px;
313
+		background-color: #333;
314
+		// border-radius: 1px;
315
+	}
316
+
317
+	/* #ifdef H5 */
318
+	@media all and (min-width: 768px) {
319
+		.uni-file-picker__files {
320
+			max-width: 375px;
321
+		}
322
+	}
323
+
324
+	/* #endif */
325
+</style>

+ 292 - 0
components/uni-file-picker/upload-image.vue

@@ -0,0 +1,292 @@
1
+<template>
2
+	<view class="uni-file-picker__container">
3
+		<view class="file-picker__box" v-for="(item,index) in filesList" :key="index" :style="boxStyle">
4
+			<view class="file-picker__box-content" :style="borderStyle">
5
+				<image class="file-image" :src="item.url" mode="aspectFill" @click.stop="prviewImage(item,index)"></image>
6
+				<view v-if="delIcon && !readonly" class="icon-del-box" @click.stop="delFile(index)">
7
+					<view class="icon-del"></view>
8
+					<view class="icon-del rotate"></view>
9
+				</view>
10
+				<view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress">
11
+					<progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4"
12
+					 :backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" />
13
+				</view>
14
+				<view v-if="item.errMsg" class="file-picker__mask" @click.stop="uploadFiles(item,index)">
15
+					点击重试
16
+				</view>
17
+			</view>
18
+		</view>
19
+		<view v-if="filesList.length < limit && !readonly" class="file-picker__box" :style="boxStyle">
20
+			<view class="file-picker__box-content is-add" :style="borderStyle" @click="choose">
21
+				<slot>
22
+					<view class="icon-add"></view>
23
+					<view class="icon-add rotate"></view>
24
+				</slot>
25
+			</view>
26
+		</view>
27
+	</view>
28
+</template>
29
+
30
+<script>
31
+	export default {
32
+		name: "uploadImage",
33
+		emits:['uploadFiles','choose','delFile'],
34
+		props: {
35
+			filesList: {
36
+				type: Array,
37
+				default () {
38
+					return []
39
+				}
40
+			},
41
+			disabled:{
42
+				type: Boolean,
43
+				default: false
44
+			},
45
+			disablePreview: {
46
+				type: Boolean,
47
+				default: false
48
+			},
49
+			limit: {
50
+				type: [Number, String],
51
+				default: 9
52
+			},
53
+			imageStyles: {
54
+				type: Object,
55
+				default () {
56
+					return {
57
+						width: 'auto',
58
+						height: 'auto',
59
+						border: {}
60
+					}
61
+				}
62
+			},
63
+			delIcon: {
64
+				type: Boolean,
65
+				default: true
66
+			},
67
+			readonly:{
68
+				type:Boolean,
69
+				default:false
70
+			}
71
+		},
72
+		computed: {
73
+			styles() {
74
+				let styles = {
75
+					width: 'auto',
76
+					height: 'auto',
77
+					border: {}
78
+				}
79
+				return Object.assign(styles, this.imageStyles)
80
+			},
81
+			boxStyle() {
82
+				const {
83
+					width = 'auto',
84
+						height = 'auto'
85
+				} = this.styles
86
+				let obj = {}
87
+				if (height === 'auto') {
88
+					if (width !== 'auto') {
89
+						obj.height = this.value2px(width)
90
+						obj['padding-top'] = 0
91
+					} else {
92
+						obj.height = 0
93
+					}
94
+				} else {
95
+					obj.height = this.value2px(height)
96
+					obj['padding-top'] = 0
97
+				}
98
+
99
+				if (width === 'auto') {
100
+					if (height !== 'auto') {
101
+						obj.width = this.value2px(height)
102
+					} else {
103
+						obj.width = '33.3%'
104
+					}
105
+				} else {
106
+					obj.width = this.value2px(width)
107
+				}
108
+
109
+				let classles = ''
110
+				for(let i in obj){
111
+					classles+= `${i}:${obj[i]};`
112
+				}
113
+				return classles
114
+			},
115
+			borderStyle() {
116
+				let {
117
+					border
118
+				} = this.styles
119
+				let obj = {}
120
+				const widthDefaultValue = 1
121
+				const radiusDefaultValue = 3
122
+				if (typeof border === 'boolean') {
123
+					obj.border = border ? '1px #eee solid' : 'none'
124
+				} else {
125
+					let width = (border && border.width) || widthDefaultValue
126
+					width = this.value2px(width)
127
+					let radius = (border && border.radius) || radiusDefaultValue
128
+					radius = this.value2px(radius)
129
+					obj = {
130
+						'border-width': width,
131
+						'border-style': (border && border.style) || 'solid',
132
+						'border-color': (border && border.color) || '#eee',
133
+						'border-radius': radius
134
+					}
135
+				}
136
+				let classles = ''
137
+				for(let i in obj){
138
+					classles+= `${i}:${obj[i]};`
139
+				}
140
+				return classles
141
+			}
142
+		},
143
+		methods: {
144
+			uploadFiles(item, index) {
145
+				this.$emit("uploadFiles", item)
146
+			},
147
+			choose() {
148
+				this.$emit("choose")
149
+			},
150
+			delFile(index) {
151
+				this.$emit('delFile', index)
152
+			},
153
+			prviewImage(img, index) {
154
+				let urls = []
155
+				if(Number(this.limit) === 1&&this.disablePreview&&!this.disabled){
156
+					this.$emit("choose")
157
+				}
158
+				if(this.disablePreview) return
159
+				this.filesList.forEach(i => {
160
+					urls.push(i.url)
161
+				})
162
+
163
+				uni.previewImage({
164
+					urls: urls,
165
+					current: index
166
+				});
167
+			},
168
+			value2px(value) {
169
+				if (typeof value === 'number') {
170
+					value += 'px'
171
+				} else {
172
+					if (value.indexOf('%') === -1) {
173
+						value = value.indexOf('px') !== -1 ? value : value + 'px'
174
+					}
175
+				}
176
+				return value
177
+			}
178
+		}
179
+	}
180
+</script>
181
+
182
+<style lang="scss">
183
+	.uni-file-picker__container {
184
+		/* #ifndef APP-NVUE */
185
+		display: flex;
186
+		box-sizing: border-box;
187
+		/* #endif */
188
+		flex-wrap: wrap;
189
+		margin: -5px;
190
+	}
191
+
192
+	.file-picker__box {
193
+		position: relative;
194
+		// flex: 0 0 33.3%;
195
+		width: 33.3%;
196
+		height: 0;
197
+		padding-top: 33.33%;
198
+		/* #ifndef APP-NVUE */
199
+		box-sizing: border-box;
200
+		/* #endif */
201
+	}
202
+
203
+	.file-picker__box-content {
204
+		position: absolute;
205
+		top: 0;
206
+		right: 0;
207
+		bottom: 0;
208
+		left: 0;
209
+		margin: 5px;
210
+		border: 1px #eee solid;
211
+		border-radius: 5px;
212
+		overflow: hidden;
213
+	}
214
+
215
+	.file-picker__progress {
216
+		position: absolute;
217
+		bottom: 0;
218
+		left: 0;
219
+		right: 0;
220
+		/* border: 1px red solid; */
221
+		z-index: 2;
222
+	}
223
+
224
+	.file-picker__progress-item {
225
+		width: 100%;
226
+	}
227
+
228
+	.file-picker__mask {
229
+		/* #ifndef APP-NVUE */
230
+		display: flex;
231
+		/* #endif */
232
+		justify-content: center;
233
+		align-items: center;
234
+		position: absolute;
235
+		right: 0;
236
+		top: 0;
237
+		bottom: 0;
238
+		left: 0;
239
+		color: #fff;
240
+		font-size: 12px;
241
+		background-color: rgba(0, 0, 0, 0.4);
242
+	}
243
+
244
+	.file-image {
245
+		width: 100%;
246
+		height: 100%;
247
+	}
248
+
249
+	.is-add {
250
+		/* #ifndef APP-NVUE */
251
+		display: flex;
252
+		/* #endif */
253
+		align-items: center;
254
+		justify-content: center;
255
+	}
256
+
257
+	.icon-add {
258
+		width: 50px;
259
+		height: 5px;
260
+		background-color: #f1f1f1;
261
+		border-radius: 2px;
262
+	}
263
+
264
+	.rotate {
265
+		position: absolute;
266
+		transform: rotate(90deg);
267
+	}
268
+
269
+	.icon-del-box {
270
+		/* #ifndef APP-NVUE */
271
+		display: flex;
272
+		/* #endif */
273
+		align-items: center;
274
+		justify-content: center;
275
+		position: absolute;
276
+		top: 3px;
277
+		right: 3px;
278
+		height: 26px;
279
+		width: 26px;
280
+		border-radius: 50%;
281
+		background-color: rgba(0, 0, 0, 0.5);
282
+		z-index: 2;
283
+		transform: rotate(-45deg);
284
+	}
285
+
286
+	.icon-del {
287
+		width: 15px;
288
+		height: 2px;
289
+		background-color: #fff;
290
+		border-radius: 2px;
291
+	}
292
+</style>

+ 109 - 0
components/uni-file-picker/utils.js

@@ -0,0 +1,109 @@
1
+/**
2
+ * 获取文件名和后缀
3
+ * @param {String} name
4
+ */
5
+export const get_file_ext = (name) => {
6
+	const last_len = name.lastIndexOf('.')
7
+	const len = name.length
8
+	return {
9
+		name: name.substring(0, last_len),
10
+		ext: name.substring(last_len + 1, len)
11
+	}
12
+}
13
+
14
+/**
15
+ * 获取扩展名
16
+ * @param {Array} fileExtname
17
+ */
18
+export const get_extname = (fileExtname) => {
19
+	if (!Array.isArray(fileExtname)) {
20
+		let extname = fileExtname.replace(/(\[|\])/g, '')
21
+		return extname.split(',')
22
+	} else {
23
+		return fileExtname
24
+	}
25
+	return []
26
+}
27
+
28
+/**
29
+ * 获取文件和检测是否可选
30
+ */
31
+export const get_files_and_is_max = (res, _extname) => {
32
+	let filePaths = []
33
+	let files = []
34
+	if(!_extname || _extname.length === 0){
35
+		return {
36
+			filePaths,
37
+			files
38
+		}
39
+	}
40
+	res.tempFiles.forEach(v => {
41
+		let fileFullName = get_file_ext(v.name)
42
+		const extname = fileFullName.ext.toLowerCase()
43
+		if (_extname.indexOf(extname) !== -1) {
44
+			files.push(v)
45
+			filePaths.push(v.path)
46
+		}
47
+	})
48
+	if (files.length !== res.tempFiles.length) {
49
+		uni.showToast({
50
+			title: `当前选择了${res.tempFiles.length}个文件 ,${res.tempFiles.length - files.length} 个文件格式不正确`,
51
+			icon: 'none',
52
+			duration: 5000
53
+		})
54
+	}
55
+
56
+	return {
57
+		filePaths,
58
+		files
59
+	}
60
+}
61
+
62
+
63
+/**
64
+ * 获取图片信息
65
+ * @param {Object} filepath
66
+ */
67
+export const get_file_info = (filepath) => {
68
+	return new Promise((resolve, reject) => {
69
+		uni.getImageInfo({
70
+			src: filepath,
71
+			success(res) {
72
+				resolve(res)
73
+			},
74
+			fail(err) {
75
+				reject(err)
76
+			}
77
+		})
78
+	})
79
+}
80
+/**
81
+ * 获取封装数据
82
+ */
83
+export const get_file_data = async (files, type = 'image') => {
84
+	// 最终需要上传数据库的数据
85
+	let fileFullName = get_file_ext(files.name)
86
+	const extname = fileFullName.ext.toLowerCase()
87
+	let filedata = {
88
+		name: files.name,
89
+		uuid: files.uuid,
90
+		extname: extname || '',
91
+		cloudPath: files.cloudPath,
92
+		fileType: files.fileType,
93
+		url: files.path || files.path,
94
+		size: files.size, //单位是字节
95
+		image: {},
96
+		path: files.path,
97
+		video: {}
98
+	}
99
+	if (type === 'image') {
100
+		const imageinfo = await get_file_info(files.path)
101
+		delete filedata.video
102
+		filedata.image.width = imageinfo.width
103
+		filedata.image.height = imageinfo.height
104
+		filedata.image.location = imageinfo.path
105
+	} else {
106
+		delete filedata.image
107
+	}
108
+	return filedata
109
+}

+ 220 - 0
components/uni-number-box/uni-number-box.vue

@@ -0,0 +1,220 @@
1
+<template>
2
+	<view class="uni-numbox">
3
+		<view @click="_calcValue('minus')" class="uni-numbox__minus uni-numbox-btns" :style="{background}">
4
+			<text class="uni-numbox--text" :class="{ 'uni-numbox--disabled': inputValue <= min || disabled }" :style="{color}">-</text>
5
+		</view>
6
+		<input :disabled="disabled" @focus="_onFocus" @blur="_onBlur" class="uni-numbox__value" type="number"
7
+			v-model="inputValue" :style="{background, color}" />
8
+		<view @click="_calcValue('plus')" class="uni-numbox__plus uni-numbox-btns" :style="{background}">
9
+			<text class="uni-numbox--text" :class="{ 'uni-numbox--disabled': inputValue >= max || disabled }" :style="{color}">+</text>
10
+		</view>
11
+	</view>
12
+</template>
13
+<script>
14
+	/**
15
+	 * NumberBox 数字输入框
16
+	 * @description 带加减按钮的数字输入框
17
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=31
18
+	 * @property {Number} value 输入框当前值
19
+	 * @property {Number} min 最小值
20
+	 * @property {Number} max 最大值
21
+	 * @property {Number} step 每次点击改变的间隔大小
22
+	 * @property {String} background 背景色
23
+	 * @property {String} color 字体颜色(前景色)
24
+	 * @property {Boolean} disabled = [true|false] 是否为禁用状态
25
+	 * @event {Function} change 输入框值改变时触发的事件,参数为输入框当前的 value
26
+	 * @event {Function} focus 输入框聚焦时触发的事件,参数为 event 对象
27
+	 * @event {Function} blur 输入框失焦时触发的事件,参数为 event 对象
28
+	 */
29
+
30
+	export default {
31
+		name: "UniNumberBox",
32
+		emits: ['change', 'input', 'update:modelValue', 'blur', 'focus'],
33
+		props: {
34
+			value: {
35
+				type: [Number, String],
36
+				default: 1
37
+			},
38
+			modelValue: {
39
+				type: [Number, String],
40
+				default: 1
41
+			},
42
+			min: {
43
+				type: Number,
44
+				default: 0
45
+			},
46
+			max: {
47
+				type: Number,
48
+				default: 100
49
+			},
50
+			step: {
51
+				type: Number,
52
+				default: 1
53
+			},
54
+			background: {
55
+				type: String,
56
+				default: '#f5f5f5'
57
+			},
58
+			color: {
59
+				type: String,
60
+				default: '#333'
61
+			},
62
+			disabled: {
63
+				type: Boolean,
64
+				default: false
65
+			}
66
+		},
67
+		data() {
68
+			return {
69
+				inputValue: 0
70
+			};
71
+		},
72
+		watch: {
73
+			value(val) {
74
+				this.inputValue = +val;
75
+			},
76
+			modelValue(val) {
77
+				this.inputValue = +val;
78
+			}
79
+		},
80
+		created() {
81
+			if (this.value === 1) {
82
+				this.inputValue = +this.modelValue;
83
+			}
84
+			if (this.modelValue === 1) {
85
+				this.inputValue = +this.value;
86
+			}
87
+		},
88
+		methods: {
89
+			_calcValue(type) {
90
+				if (this.disabled) {
91
+					return;
92
+				}
93
+				const scale = this._getDecimalScale();
94
+				let value = this.inputValue * scale;
95
+				let step = this.step * scale;
96
+				if (type === "minus") {
97
+					value -= step;
98
+					if (value < (this.min * scale)) {
99
+						return;
100
+					}
101
+					if (value > (this.max * scale)) {
102
+						value = this.max * scale
103
+					}
104
+				}
105
+
106
+				if (type === "plus") {
107
+					value += step;
108
+					if (value > (this.max * scale)) {
109
+						return;
110
+					}
111
+					if (value < (this.min * scale)) {
112
+						value = this.min * scale
113
+					}
114
+				}
115
+
116
+				this.inputValue = (value / scale).toFixed(String(scale).length - 1);
117
+				this.$emit("change", +this.inputValue);
118
+				// TODO vue2 兼容
119
+				this.$emit("input", +this.inputValue);
120
+				// TODO vue3 兼容
121
+				this.$emit("update:modelValue", +this.inputValue);
122
+			},
123
+			_getDecimalScale() {
124
+
125
+				let scale = 1;
126
+				// 浮点型
127
+				if (~~this.step !== this.step) {
128
+					scale = Math.pow(10, String(this.step).split(".")[1].length);
129
+				}
130
+				return scale;
131
+			},
132
+			_onBlur(event) {
133
+				this.$emit('blur', event)
134
+				let value = event.detail.value;
135
+				if (!value) {
136
+					// this.inputValue = 0;
137
+					return;
138
+				}
139
+				value = +value;
140
+				if (value > this.max) {
141
+					value = this.max;
142
+				} else if (value < this.min) {
143
+					value = this.min;
144
+				}
145
+				const scale = this._getDecimalScale();
146
+				this.inputValue = value.toFixed(String(scale).length - 1);
147
+				this.$emit("change", +this.inputValue);
148
+				this.$emit("input", +this.inputValue);
149
+			},
150
+			_onFocus(event) {
151
+				this.$emit('focus', event)
152
+			}
153
+		}
154
+	};
155
+</script>
156
+<style lang="scss" scoped>
157
+	$box-height: 26px;
158
+	$bg: #f5f5f5;
159
+	$br: 2px;
160
+	$color: #333;
161
+
162
+	.uni-numbox {
163
+		/* #ifndef APP-NVUE */
164
+		display: flex;
165
+		/* #endif */
166
+		flex-direction: row;
167
+	}
168
+
169
+	.uni-numbox-btns {
170
+		/* #ifndef APP-NVUE */
171
+		display: flex;
172
+		/* #endif */
173
+		flex-direction: row;
174
+		align-items: center;
175
+		justify-content: center;
176
+		padding: 0 8px;
177
+		background-color: $bg;
178
+		/* #ifdef H5 */
179
+		cursor: pointer;
180
+		/* #endif */
181
+	}
182
+
183
+	.uni-numbox__value {
184
+		margin: 0 2px;
185
+		background-color: $bg;
186
+		width: 40px;
187
+		height: $box-height;
188
+		text-align: center;
189
+		font-size: 14px;
190
+		border-left-width: 0;
191
+		border-right-width: 0;
192
+		color: $color;
193
+	}
194
+
195
+	.uni-numbox__minus {
196
+		border-top-left-radius: $br;
197
+		border-bottom-left-radius: $br;
198
+	}
199
+
200
+	.uni-numbox__plus {
201
+		border-top-right-radius: $br;
202
+		border-bottom-right-radius: $br;
203
+	}
204
+
205
+	.uni-numbox--text {
206
+		// fix nvue
207
+		line-height: 20px;
208
+
209
+		font-size: 20px;
210
+		font-weight: 300;
211
+		color: $color;
212
+	}
213
+
214
+	.uni-numbox .uni-numbox--disabled {
215
+		color: #c0c0c0 !important;
216
+		/* #ifdef H5 */
217
+		cursor: not-allowed;
218
+		/* #endif */
219
+	}
220
+</style>

+ 26 - 2
pages.json

@@ -49,7 +49,7 @@
49 49
           "titleNView": false
50 50
         }
51 51
       }
52
-    },{
52
+    }, {
53 53
       "path": "pages/scanning_result_seimin/scanning_result_seimin", //药包扫描----知道了
54 54
       "style": {
55 55
         "h5": {
@@ -82,7 +82,8 @@
82 82
       "style": {
83 83
         "h5": {
84 84
           "titleNView": false
85
-        }
85
+        },
86
+        "enablePullDownRefresh": true
86 87
       }
87 88
     }, {
88 89
       "path": "pages/scanning_all/scanning_all", //大扫描->科室->正确
@@ -211,6 +212,29 @@
211 212
         "enablePullDownRefresh": false
212 213
       }
213 214
 
215
+    }, {
216
+      "path": "pages/specimenCheckingDetail/specimenCheckingDetail",
217
+      "style": {
218
+        "h5": {
219
+          "titleNView": false
220
+        },
221
+        "enablePullDownRefresh": true
222
+      }
223
+    }, {
224
+      "path": "pages/checkNumberPage/checkNumberPage",
225
+      "style": {
226
+        "h5": {
227
+          "titleNView": false
228
+        }
229
+      }
230
+    }, {
231
+      "path": "pages/checkNumberDetail/checkNumberDetail",
232
+      "style": {
233
+        "h5": {
234
+          "titleNView": false
235
+        },
236
+        "enablePullDownRefresh": true
237
+      }
214 238
     }
215 239
   ],
216 240
   "globalStyle": {

+ 625 - 0
pages/checkNumberDetail/checkNumberDetail.vue

@@ -0,0 +1,625 @@
1
+<template>
2
+  <view class="specimenCheckingDetail">
3
+    <view class="page_header">
4
+      <view class="page_header_item">
5
+        <view class="page_header_title">
6
+          修改原因:
7
+        </view>
8
+        <view class="page_header_content">
9
+          我是你的爸爸
10
+        </view>
11
+      </view>
12
+      <view class="page_header_item">
13
+        <view class="page_header_title">
14
+          图片列表:
15
+        </view>
16
+        <view class="page_header_content">
17
+          <image v-for="(item,i) in imgs" :key="i" :src="item" @click="previewImage(i)" mode="widthFix"></image>
18
+        </view>
19
+      </view>
20
+    </view>
21
+    <view class="page_item_wrap" v-for="item in list" :key="item.id">
22
+      <view class="page_item">
23
+        <view class="page_item_top">
24
+          <view class="page_item_top-inner">
25
+            <view class="page_item_top_L">
26
+              <view class="L_text">{{item.patientName}}</view>
27
+            </view>
28
+            <view class="page_item_top_R">
29
+              <view class="L_iocn"><button type="primary" size="mini" class="back">退回</button></view>
30
+            </view>
31
+          </view>
32
+        </view>
33
+        <view class="page_item_cont">
34
+          <view class="page_item_cont_T">
35
+            <view class="page_item_cont_title">
36
+              <view>
37
+                检验项目
38
+              </view>
39
+              <view class="text_big">{{item.specimenDesc||'无'}}</view>
40
+            </view>
41
+            <view class="page_item_cont_title">
42
+              <view>
43
+                标本编码
44
+              </view>
45
+              <view class="text_big">{{item.scode||'无'}}</view>
46
+            </view>
47
+            <view class="page_item_cont_title">
48
+              <view>
49
+                标本类型
50
+              </view>
51
+              <view class="text_big">{{item.stype?item.stype.name:'无'}}</view>
52
+            </view>
53
+            <view class="page_item_cont_title">
54
+              <view>
55
+                申请科室
56
+              </view>
57
+              <view class="text_big">{{item.sickRoom?item.sickRoom.dept:'无'}}</view>
58
+            </view>
59
+            <view class="page_item_cont_title">
60
+              <view>
61
+                住院号
62
+              </view>
63
+              <view class="text_big">{{item.residenceNo||'无'}}</view>
64
+            </view>
65
+          </view>
66
+        </view>
67
+        <view class="L"></view>
68
+        <view class="R"></view>
69
+      </view>
70
+      <view class="L-l"></view>
71
+      <view class="R-l"></view>
72
+    </view>
73
+    <view class="foot_btn2"></view>
74
+    <!-- 退回弹窗 -->
75
+    <backModel v-if="backModels.disjunctor" :title="backModels.title" :disjunctor="backModels.disjunctor" @ok="backOk"
76
+      @cancel="backCancel"></backModel>
77
+    <!-- 填写交接人账号弹窗 -->
78
+    <selectAccount v-if="hosModels.disjunctor" :title="hosModels.title" :disjunctor="hosModels.disjunctor" @ok="hosOk"
79
+      @cancel="hosCancel">
80
+    </selectAccount>
81
+    <!-- 弹窗 -->
82
+    <showModel :title="models.title" :icon="models.icon" :disjunctor="models.disjunctor" :content="models.content"
83
+      :operate="models.operate" @know="know"></showModel>
84
+  </view>
85
+</template>
86
+<script>
87
+  import {
88
+    get,
89
+    post,
90
+    webHandle
91
+  } from "../../http/http.js";
92
+  export default {
93
+    data() {
94
+      return {
95
+        res: {},
96
+        backSpecimen: {},
97
+        backParams: {},
98
+        imgs: ['https://img1.baidu.com/it/u=3217543765,3223180824&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=750',
99
+          'https://img1.baidu.com/it/u=3217543765,3223180824&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=750',
100
+          'https://img1.baidu.com/it/u=3217543765,3223180824&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=750'
101
+        ],
102
+        startDeptId: null,
103
+        deptId: null,
104
+        msg: {}, //传递的信息
105
+        list: [],
106
+        targetDeptShow: [], //目标科室
107
+        // 填写交接人账号弹窗model
108
+        hosModels: {
109
+          disjunctor: false,
110
+        },
111
+        // 退回弹窗model
112
+        backModels: {
113
+          disjunctor: false,
114
+        },
115
+        // 弹窗model
116
+        models: {
117
+          disjunctor: false,
118
+        },
119
+      };
120
+    },
121
+    methods: {
122
+      // 退回
123
+      backHandler(specimen, workorderId, data) {
124
+        console.log(specimen);
125
+        const {
126
+          reasonForReturn,
127
+          remarks,
128
+        } = this.backParams;
129
+        uni.showLoading({
130
+          title: '加载中',
131
+          mask: true
132
+        })
133
+        let postData = {
134
+          reasonForReturn,
135
+          remarks,
136
+          scode: specimen.scode,
137
+          hosId: uni.getStorageSync("userData").user.currentHospital.id,
138
+          speState: specimen.speState ? specimen.speState.id : undefined,
139
+          handoverId: data ? data.accountId : undefined,
140
+          handoverName: data ? data.accountName : undefined,
141
+          gdId: workorderId || undefined,
142
+        }
143
+        post('/workerOrder/returnSpecimen', postData).then(res => {
144
+          uni.hideLoading();
145
+          if (res.state == 200) {
146
+            this.models = {
147
+              disjunctor: true,
148
+              title: "提示",
149
+              content: `标本退回成功`,
150
+              icon: "success",
151
+            };
152
+          } else {
153
+            this.models = {
154
+              disjunctor: true,
155
+              title: "提示",
156
+              content: `标本退回失败`,
157
+              icon: "error",
158
+            };
159
+          }
160
+        })
161
+      },
162
+      // 填写交接人账号-确认
163
+      hosOk(data) {
164
+        console.log(data);
165
+        const {
166
+          accountName,
167
+          account,
168
+          accountId
169
+        } = data;
170
+        if (!accountName && !account) {
171
+          //没有填写交接人
172
+          uni.showModal({
173
+            title: "提示",
174
+            content: "请填写交接人账号!",
175
+            showCancel: false,
176
+            success: function(res) {
177
+              if (res.confirm) {
178
+                console.log("用户点击确定");
179
+              } else if (res.cancel) {
180
+                console.log("用户点击取消");
181
+              }
182
+            },
183
+          });
184
+          return;
185
+        } else if ((!accountName && account) || (accountName && !account)) {
186
+          //没有填写交接人
187
+          uni.showModal({
188
+            title: "提示",
189
+            content: "请填写正确的交接人账号!",
190
+            showCancel: false,
191
+            success: function(res) {
192
+              if (res.confirm) {
193
+                console.log("用户点击确定");
194
+              } else if (res.cancel) {
195
+                console.log("用户点击取消");
196
+              }
197
+            },
198
+          });
199
+          return;
200
+        }
201
+        this.hosModels.disjunctor = false;
202
+        uni.showLoading({
203
+          title: "加载中",
204
+          mask: true,
205
+        });
206
+        if (this.backStatus = 'back') {
207
+          // 退回
208
+          this.backHandler(this.backSpecimen, this.res.data.gdid, data);
209
+        } else {
210
+          this.nextDeptOrder_s(this.res.workOrder, data);
211
+        }
212
+      },
213
+      // 填写交接人账号-取消
214
+      hosCancel() {
215
+        this.hosModels.disjunctor = false;
216
+      },
217
+      // 填写交接人账号弹窗
218
+      showSelectAccount() {
219
+        this.hosModels = {
220
+          title: "填写交接人账号",
221
+          disjunctor: true,
222
+        };
223
+      },
224
+      // 退回-确认
225
+      backOk(data) {
226
+        console.log(data);
227
+        this.backParams = data;
228
+        this.hosModels.disjunctor = false;
229
+        let postData = {
230
+          "idx": 0,
231
+          "sum": 1,
232
+          "hospitalConfig": {
233
+            "hosId": uni.getStorageSync("userData").user.currentHospital.id,
234
+            "key": "returnSpecimenWhetherHandover"
235
+          }
236
+        };
237
+        uni.showLoading({
238
+          title: "加载中",
239
+          mask: true,
240
+        });
241
+        post('/simple/data/fetchDataList/hospitalConfig', postData).then((result) => {
242
+          uni.hideLoading();
243
+          if (result.status == 200) {
244
+            if (result.list[0].value == 1) {
245
+              this.showSelectAccount();
246
+            } else {
247
+              this.backHandler(this.backSpecimen, this.workOrderId);
248
+            }
249
+          } else {
250
+            uni.showToast({
251
+              icon: "none",
252
+              title: "请求失败!",
253
+            });
254
+          }
255
+        })
256
+      },
257
+      // 退回-取消
258
+      backCancel() {
259
+        this.backModels.disjunctor = false;
260
+      },
261
+      // 退回弹窗
262
+      showBack() {
263
+        this.backModels = {
264
+          title: "退回",
265
+          disjunctor: true,
266
+        };
267
+      },
268
+      previewImage(index) {
269
+        //uniapp预览轮播图
270
+        uni.previewImage({
271
+          current: index, //预览图片的下标
272
+          urls: this.imgs //预览图片的地址,必须要数组形式,如果不是数组形式就转换成数组形式就可以
273
+        })
274
+      },
275
+      getList() {
276
+        uni.showLoading({
277
+          mask: true,
278
+          title: '加载中'
279
+        })
280
+        let postData = [Number(this.startDeptId), Number(this.deptId)]; //起点科室id,选择的科室id
281
+        post(`/api/getTransDeptSpecimens`, postData).then((res) => {
282
+          uni.hideLoading();
283
+          uni.stopPullDownRefresh();
284
+          if (res.status == 200) {
285
+            this.list = res.data;
286
+          } else {
287
+            uni.showToast({
288
+              icon: "none",
289
+              title: "请求失败!",
290
+            });
291
+          }
292
+        });
293
+      },
294
+      // 返回
295
+      goto() {
296
+        uni.navigateTo({
297
+          url: `../../pages/specimenChecking/specimenChecking?infoDATA=${encodeURIComponent(JSON.stringify(this.msg))}`,
298
+        });
299
+      },
300
+    },
301
+    onLoad(options) {
302
+      console.log(options, "快捷建单");
303
+      this.msg = JSON.parse(options.infoDATA);
304
+      this.startDeptId = options.startDeptId;
305
+      this.deptId = options.deptId;
306
+      this.getList();
307
+      // #ifdef APP-PLUS
308
+      webHandle("no", "app");
309
+      // #endif
310
+      // #ifdef H5
311
+      webHandle("no", "wx");
312
+      // #endif
313
+    },
314
+    onPullDownRefresh() {
315
+      this.getList();
316
+    },
317
+  };
318
+</script>
319
+<style lang="less" scoped>
320
+  .specimenCheckingDetail {
321
+    padding-bottom: 100rpx;
322
+
323
+    .page_header {
324
+      margin: 20rpx;
325
+      padding: 16rpx;
326
+      border: 2rpx solid #e5e9ed;
327
+      background: #fff;
328
+      border-radius: 8rpx;
329
+
330
+      .page_header_item {
331
+        margin-bottom: 16rpx;
332
+
333
+        .page_header_title {
334
+          margin-bottom: 8rpx;
335
+          font-weight: bold;
336
+        }
337
+
338
+        .page_header_content {
339
+          display: flex;
340
+
341
+          image {
342
+            flex: 1;
343
+            margin: 0 8rpx;
344
+          }
345
+        }
346
+      }
347
+    }
348
+
349
+    .page_item_wrap {
350
+      width: 100%;
351
+      height: auto;
352
+      box-sizing: border-box;
353
+      position: relative;
354
+      margin-bottom: 16rpx;
355
+
356
+      .page_item {
357
+        margin-top: 16rpx;
358
+        margin-bottom: 124rpx;
359
+        background: #fff;
360
+        border-radius: 8rpx;
361
+        margin: 0 20rpx;
362
+        border: 2rpx solid #e5e9ed;
363
+        position: relative;
364
+        overflow: hidden;
365
+        padding: 0 16rpx;
366
+
367
+        .L {
368
+          width: 40rpx;
369
+          height: 40rpx;
370
+          border-radius: 50%;
371
+          background: #f9fafb;
372
+          position: absolute;
373
+          left: -20rpx;
374
+          top: 68rpx;
375
+          border: 2rpx solid #e5e9ed;
376
+        }
377
+
378
+        .R {
379
+          width: 40rpx;
380
+          height: 40rpx;
381
+          border-radius: 50%;
382
+          background: #f9fafb;
383
+          position: absolute;
384
+          float: right;
385
+          right: -20rpx;
386
+          top: 68rpx;
387
+          border: 2rpx solid #e5e9ed;
388
+        }
389
+
390
+        .starting {
391
+          width: 50rpx;
392
+          height: 50rpx;
393
+          color: #fff;
394
+          background: #49b856;
395
+          display: inline-block;
396
+          border-radius: 50%;
397
+          text-align: center;
398
+          line-height: 46rpx;
399
+          font-size: 32rpx;
400
+          margin-right: 6rpx;
401
+        }
402
+
403
+        .End {
404
+          width: 50rpx;
405
+          height: 50rpx;
406
+          color: #fff;
407
+          background: #39b199;
408
+          display: inline-block;
409
+          border-radius: 50%;
410
+          text-align: center;
411
+          line-height: 46rpx;
412
+          font-size: 32rpx;
413
+          margin-right: 6rpx;
414
+        }
415
+
416
+        .page_item_top {
417
+          height: 88rpx;
418
+          border-bottom: 2rpx dashed #e5e9ed;
419
+          padding: 0 16rpx;
420
+
421
+          .page_item_top-inner {
422
+            display: flex;
423
+            justify-content: space-between;
424
+            align-items: center;
425
+            height: 100%;
426
+
427
+            .page_item_top_L {
428
+              .emergencys {
429
+                background: #ff3b53 !important;
430
+                width: 124rpx !important;
431
+              }
432
+
433
+              .emergency {
434
+                background: #ff3b53 !important;
435
+              }
436
+
437
+              .emergency1 {
438
+                background: #49b856 !important;
439
+              }
440
+
441
+              .page_item_cont_start {
442
+                text-align: center;
443
+                height: 44rpx;
444
+                width: 104rpx;
445
+                line-height: 44rpx;
446
+                border-radius: 8rpx;
447
+                background: #49b856;
448
+                color: #fff;
449
+                display: inline-block;
450
+              }
451
+
452
+              .L_time {
453
+                color: #6cc076;
454
+                font-size: 32rpx;
455
+              }
456
+
457
+              .L_text {
458
+                font-size: 32rpx;
459
+                font-weight: 700;
460
+              }
461
+            }
462
+
463
+            .page_item_top_R {
464
+              font-size: 32rpx;
465
+
466
+              .back {
467
+                background-color: #49b856;
468
+              }
469
+
470
+              .L_iocn {
471
+                color: rgb(7, 134, 60);
472
+                font-size: 36rpx;
473
+                font-weight: 700;
474
+              }
475
+            }
476
+          }
477
+        }
478
+
479
+        .page_item_cont {
480
+          min-height: 90rpx;
481
+          padding: 0 16rpx;
482
+          text-align: left;
483
+          position: relative;
484
+
485
+          .text_big {
486
+            font-size: 32rpx;
487
+            font-weight: 700;
488
+            margin-top: 10rpx;
489
+
490
+            p {
491
+              font-weight: 700;
492
+              line-height: 1.5;
493
+            }
494
+          }
495
+
496
+          .page_item_cont_T {
497
+            padding-top: 28rpx;
498
+            padding-bottom: 28rpx;
499
+            font-size: 28rpx;
500
+
501
+            .page_item_cont_title {
502
+              height: 100%;
503
+              font-size: 32rpx;
504
+              display: flex;
505
+              justify-content: space-between;
506
+            }
507
+          }
508
+
509
+          .page_item_cont_B {
510
+            padding-top: 28rpx;
511
+            margin-bottom: 28rpx;
512
+
513
+            .page_item_cont_title {
514
+              font-size: 32rpx;
515
+              display: flex;
516
+              justify-content: space-between;
517
+            }
518
+
519
+            .page_item_cont_title1 {
520
+              height: 60rpx;
521
+              line-height: 60rpx;
522
+              font-size: 32rpx;
523
+              padding-left: 64rpx;
524
+            }
525
+          }
526
+        }
527
+
528
+        .page_item_foot {
529
+          border-top: 2rpx dashed #e5e9ed;
530
+          border-bottom: 2rpx dashed #e5e9ed;
531
+          padding: 28rpx 16rpx;
532
+          text-align: left;
533
+
534
+          .page_item_foot_text {
535
+            font-size: 32rpx;
536
+            margin-bottom: 20rpx;
537
+
538
+            .text1 {
539
+              color: rgb(102, 102, 102);
540
+            }
541
+
542
+            .text2 {
543
+              float: right;
544
+              font-weight: 700;
545
+            }
546
+          }
547
+        }
548
+
549
+        #infos {
550
+          display: none;
551
+        }
552
+
553
+        .page_item_infos {
554
+          padding-bottom: 20rpx;
555
+          border-bottom: 2rpx dashed #e5e9ed;
556
+
557
+          .page_item_info2 {
558
+            text-align: left;
559
+            line-height: 60rpx;
560
+            font-size: 32rpx;
561
+            padding-left: 16rpx;
562
+
563
+            .page_item_foot_text {
564
+              font-size: 32rpx;
565
+              margin-bottom: 20rpx;
566
+
567
+              .text1 {
568
+                color: rgb(102, 102, 102);
569
+              }
570
+
571
+              .text2 {
572
+                float: right;
573
+                font-weight: 700;
574
+              }
575
+            }
576
+          }
577
+        }
578
+      }
579
+
580
+      .L-l {
581
+        width: 2rpx;
582
+        height: 40rpx;
583
+        background: #f9fafb;
584
+        position: absolute;
585
+        left: 20rpx;
586
+        top: 72rpx;
587
+      }
588
+
589
+      .R-l {
590
+        width: 2rpx;
591
+        height: 40rpx;
592
+        background: #f9fafb;
593
+        position: absolute;
594
+        right: 20rpx;
595
+        top: 72rpx;
596
+      }
597
+    }
598
+
599
+    .foot_btn2 {
600
+      position: fixed;
601
+      bottom: 0;
602
+      width: 100vw;
603
+      padding: 0 20rpx;
604
+      box-sizing: border-box;
605
+      line-height: 66rpx;
606
+      height: 100rpx;
607
+      border-top: 2rpx solid #e5e9ed;
608
+      background: #f9fafb;
609
+      text-align: center;
610
+      display: flex;
611
+      justify-content: center;
612
+      align-items: center;
613
+
614
+      .btn2 {
615
+        height: 66rpx;
616
+        flex: 1;
617
+        margin: 16rpx 16rpx 0;
618
+        background-image: linear-gradient(to right, #72c172, #3bb197);
619
+        color: #fff;
620
+        border-radius: 8rpx;
621
+        font-size: 32rpx;
622
+      }
623
+    }
624
+  }
625
+</style>

+ 222 - 0
pages/checkNumberPage/checkNumberPage.vue

@@ -0,0 +1,222 @@
1
+<template>
2
+  <view class="checkNumberPage">
3
+    <view class="title">请填写本次您送达的标本数量!</view>
4
+    <view class="page_item_wrap">
5
+      <view class="changeSpeNum__article">
6
+        <view class="uni-list-cell">
7
+          <view class="uni-list-cell-left">
8
+            标本数量:
9
+          </view>
10
+          <view class="uni-list-cell-db">
11
+            <uni-number-box v-model="speNum"></uni-number-box>
12
+          </view>
13
+        </view>
14
+        <view class="uni-list-cell" v-if="speNum != num">
15
+          <view class="uni-list-cell-left">
16
+            上传图片:
17
+          </view>
18
+          <view class="uni-list-cell-db">
19
+            <uni-file-picker :auto-upload="false" :limit="3" title="最多选择3张图片" v-model="imageValue" fileMediatype="image"
20
+              mode="grid" @select="selectFile" @delete="deleteFile"></uni-file-picker>
21
+          </view>
22
+        </view>
23
+      </view>
24
+    </view>
25
+    <view class="foot_btn2">
26
+      <view class="btn2" @click="createOrder">确认数量</view>
27
+      <view class="btn2" @click="goto()">查看标本</view>
28
+    </view>
29
+  </view>
30
+</template>
31
+<script>
32
+  import {
33
+    get,
34
+    post,
35
+    webHandle
36
+  } from "../../http/http.js";
37
+  export default {
38
+    data() {
39
+      return {
40
+        options: {},
41
+        imageValue: [], //图片列表
42
+        speNum: 0, //修改后的数量
43
+        num: 0,
44
+        reason: undefined, //修改原因
45
+        msg: {}, //页面展示信息
46
+      };
47
+    },
48
+    methods: {
49
+      // 获取上传状态
50
+      selectFile(e) {
51
+        console.log('选择文件:', e)
52
+        this.imageValue = this.imageValue.concat(e.tempFiles);
53
+      },
54
+
55
+      // 移除
56
+      deleteFile(e) {
57
+        console.log('移除:', e);
58
+        this.imageValue = this.imageValue.filter(v => v.uuid != e.tempFile.uuid);
59
+      },
60
+      // 获取信息
61
+      getInfo() {
62
+        uni.showLoading({
63
+          mask: true,
64
+          title: '加载中'
65
+        })
66
+        let postData = {
67
+          deptId: this.options.deptId,
68
+          gdId: this.msg.id
69
+        };
70
+        post(`/api/getStartDeptSpecimensNum`, postData).then((res) => {
71
+          uni.hideLoading();
72
+          if (res.status == 200) {
73
+            this.speNum = res.deptSpecimensNum;
74
+          } else {
75
+            uni.showToast({
76
+              icon: "none",
77
+              title: "请求失败!",
78
+            });
79
+          }
80
+        });
81
+      },
82
+      // 查看标本
83
+      goto() {
84
+        uni.navigateTo({
85
+          url: `../../pages/checkNumberDetail/checkNumberDetail?startDeptId=${this.msg.startDept.id}&deptId=${this.options.deptId}`,
86
+        });
87
+      },
88
+      // 确认数量并建单
89
+      createOrder() {
90
+        uni.showModal({
91
+          title: '提示',
92
+          content: "您确认建单吗?",
93
+          success: (res) => {
94
+            if (res.confirm) {
95
+              console.log('用户点击确定');
96
+              uni.showLoading({
97
+                mask: true,
98
+                title: '加载中'
99
+              })
100
+              get(`/workerOrder/createQuickOrder/${this.msg.id}`, {}).then((res) => {
101
+                console.log(res)
102
+                uni.hideLoading();
103
+                if (res.status == 200) {
104
+                  if (res.type === 'plan-spe-ddd-2') {
105
+                    //需要扫描标本
106
+                    uni.navigateTo({
107
+                      url: `../../pages/scanning_code/scanning_code?type=${res.associationTypeName}&type1=${res.type}&id=${res.id}&deptCode=${res.deptCode}&dept=${res.deptName}&accountObj=undefined`,
108
+                    });
109
+                  } else {
110
+                    uni.navigateTo({
111
+                      url: "../receiptpage/receiptpage",
112
+                    });
113
+                  }
114
+                } else {
115
+                  uni.showToast({
116
+                    icon: "none",
117
+                    title: "请求失败!",
118
+                  });
119
+                }
120
+              });
121
+            } else if (res.cancel) {
122
+              console.log('用户点击取消');
123
+            }
124
+          }
125
+        });
126
+      },
127
+    },
128
+    onLoad(options) {
129
+      console.log(options, "快捷建单");
130
+      this.options = options;
131
+      this.msg = JSON.parse(options.infoDATA);
132
+      this.getInfo();
133
+      // #ifdef APP-PLUS
134
+      webHandle("no", "app");
135
+      // #endif
136
+      // #ifdef H5
137
+      webHandle("no", "wx");
138
+      // #endif
139
+    },
140
+  };
141
+</script>
142
+<style lang="less" scoped>
143
+  .checkNumberPage {
144
+    padding-bottom: 100rpx;
145
+
146
+    .title {
147
+      font-size: 48rpx;
148
+      margin-top: 24rpx;
149
+      margin-bottom: 24rpx;
150
+      text-align: center;
151
+    }
152
+
153
+    .page_item_wrap {
154
+      width: 100%;
155
+      height: auto;
156
+      box-sizing: border-box;
157
+      position: relative;
158
+      margin-bottom: 16rpx;
159
+
160
+      .uni-list-cell {
161
+        width: 94%;
162
+        display: flex;
163
+        flex-direction: row;
164
+        justify-content: space-evenly;
165
+        align-items: center;
166
+        text-align: center;
167
+        margin-top: 32rpx;
168
+
169
+        .uni-list-cell-left {
170
+          flex: 2;
171
+          font-size: 32rpx;
172
+          color: #666;
173
+        }
174
+
175
+        .uni-list-cell-db {
176
+          padding: 16rpx 0;
177
+          flex: 5;
178
+        }
179
+
180
+        .uni-list-cell-db-text {
181
+          border: 1px solid #e5e9ed;
182
+          background-color: #fff;
183
+          flex: 5;
184
+          text-align: left;
185
+
186
+          textarea {
187
+            width: 100%;
188
+            box-sizing: border-box;
189
+            padding: 0 8rpx;
190
+            max-height: 150rpx;
191
+          }
192
+        }
193
+      }
194
+    }
195
+
196
+    .foot_btn2 {
197
+      position: fixed;
198
+      bottom: 0;
199
+      width: 100vw;
200
+      padding: 0 20rpx;
201
+      box-sizing: border-box;
202
+      line-height: 66rpx;
203
+      height: 100rpx;
204
+      border-top: 2rpx solid #e5e9ed;
205
+      background: #f9fafb;
206
+      text-align: center;
207
+      display: flex;
208
+      justify-content: center;
209
+      align-items: center;
210
+
211
+      .btn2 {
212
+        height: 66rpx;
213
+        flex: 1;
214
+        margin: 16rpx 16rpx 0;
215
+        background-image: linear-gradient(to right, #72c172, #3bb197);
216
+        color: #fff;
217
+        border-radius: 8rpx;
218
+        font-size: 32rpx;
219
+      }
220
+    }
221
+  }
222
+</style>

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 818 - 916
pages/scanning_all/scanning_all.vue


+ 29 - 9
pages/scanning_code/scanning_code.vue

@@ -312,6 +312,7 @@
312 312
       ">
313 313
       <view class="btn3" @click="Scanning_again(dataId)">继续扫描</view>
314 314
       <view class="btn3" @click="showHandViewSpecimen()">手动录入</view>
315
+      <view class="btn3" v-if="infoDATA.taskType.isDigitalHandover==1" @click="checkNumber(infoDATA)">数量核对</view>
315 316
       <view class="btn3" @click="next()" v-if="queryObj.fromSpecimenBuild">下一步</view>
316 317
     </view>
317 318
     <view class="foot_btn2 footerPadding" v-if="
@@ -407,6 +408,23 @@
407 408
       };
408 409
     },
409 410
     methods: {
411
+      // 数量核对
412
+      checkNumber(infoDATA) {
413
+        let deptId = this.queryObj.deptId;
414
+        let endDepts = this.queryObj.endDepts;
415
+        console.log(endDepts,'scanning_code')
416
+        if (deptId) {
417
+          // 小扫描
418
+          uni.navigateTo({
419
+            url: `/pages/specimenCheckingDetail/specimenCheckingDetail?infoDATA=${encodeURIComponent(JSON.stringify({startDept:this.infoDATA.startDept.id,uuid:this.infoDATA.id}))}&id=${deptId}&t=small&gdState=${this.infoDATA.gdState.value}&endDepts=${endDepts}`
420
+          })
421
+        } else {
422
+          // 快捷建单进入小扫描
423
+          uni.navigateTo({
424
+            url: `/pages/specimenCheckingDetail/specimenCheckingDetail?infoDATA=${encodeURIComponent(JSON.stringify({startDept:this.infoDATA.startDept.id,uuid:this.infoDATA.id}))}&id=${deptId}&t=small&endDepts=${endDepts}`
425
+          })
426
+        }
427
+      },
410 428
       // 手动查询药品-确认
411 429
       drugbagOk(data) {
412 430
         console.log(data);
@@ -474,18 +492,20 @@
474 492
         }
475 493
       },
476 494
       // 下一步
477
-      next(){
495
+      next() {
478 496
         uni.showLoading({
479
-          title:'加载中',
480
-          mask:true,
497
+          title: '加载中',
498
+          mask: true,
481 499
         })
482
-        post('/workerOrder/getSpecimenCount',{gdId:this.queryObj.id}).then(res=>{
500
+        post('/workerOrder/getSpecimenCount', {
501
+          gdId: this.queryObj.id
502
+        }).then(res => {
483 503
           get('/api/fetchData/specimen/' + this.queryObj.specimenId).then(ress => {
484 504
             uni.hideLoading();
485 505
             console.log(ress);
486
-            ress.msg='成功';
506
+            ress.msg = '成功';
487 507
             ress.specimenCount = res.specimenCount;
488
-            ress.type=this.queryObj.type1;
508
+            ress.type = this.queryObj.type1;
489 509
             uni.navigateTo({
490 510
               url: `../scanning_Result/scanning_Result?type=${
491 511
               this.queryObj.type
@@ -576,9 +596,9 @@
576 596
                   if (this.infoDATA.taskType.associationType.value == 'specimen' || this.infoDATA.taskType
577 597
                     .associationType.value == 'specimenPlan') {
578 598
                     if (type === 'scan') {
579
-                      setTimeout(()=>{
599
+                      setTimeout(() => {
580 600
                         this.Scanning_again(this.dataId);
581
-                      },500)
601
+                      }, 500)
582 602
                     }
583 603
                   }
584 604
                   if (
@@ -1239,7 +1259,7 @@
1239 1259
       .btn2 {
1240 1260
         height: 66rpx;
1241 1261
         flex: 1;
1242
-        margin:0 1%;
1262
+        margin: 0 1%;
1243 1263
         background-image: linear-gradient(to right, #72c172, #3bb197);
1244 1264
         color: #fff;
1245 1265
         border-radius: 8rpx;

+ 38 - 4
pages/scanning_djEnd/scanning_djEnd.vue

@@ -127,7 +127,7 @@
127 127
           type1 === 'jp-dsd-1'
128 128
         ">知道了</view>
129 129
     </view>
130
-    <view class="foot_btn" v-if="
130
+    <view class="foot_btn_spe" v-if="
131 131
         (type == 'specimenPlan' &&
132 132
           type1 != 'plan-spe-dsd-1' &&
133 133
           (type1 != 'plan-spe-ddd-1') & (type1 != 'plan-spe-ddd-2')) ||
@@ -139,8 +139,9 @@
139 139
       <view class="btn3" @click="showHandViewSpecimen()">手动录入</view>
140 140
       <view class="btn3" @click="getNoScanSpecimen()">未扫描标本</view>
141 141
       <view class="btn2" @click="Scanning_complete(ids)">完成扫描</view>
142
+      <view class="btn2" @click="checkNumber()" v-if="queryObj.isDigitalHandover==1">数量核对</view>
142 143
     </view>
143
-    <view class="foot_btn" v-if="
144
+    <view class="foot_btn_spe" v-if="
144 145
         (type == 'specimenPlan' && type1 == 'plan-spe-ddd-2') ||
145 146
         (type == 'specimen' && type1 == 'spe-ddd-2')
146 147
       ">
@@ -148,6 +149,7 @@
148 149
       <view class="btn3" @click="showHandViewSpecimen()">手动录入</view>
149 150
       <view class="btn3" @click="getNoScanSpecimen()">未扫描标本</view>
150 151
       <view class="btn2" @click="Scanning_complete(ids)">完成扫描</view>
152
+      <view class="btn2" @click="checkNumber()" v-if="queryObj.isDigitalHandover==1">数量核对</view>
151 153
     </view>
152 154
     <view class="foot_btn" v-if="
153 155
         (infoDATA.state != 'finish' &&
@@ -248,6 +250,12 @@
248 250
       };
249 251
     },
250 252
     methods: {
253
+      // 数量核对 queryObj
254
+      checkNumber() {
255
+        uni.navigateTo({
256
+          url: `/pages/specimenCheckingDetail/specimenCheckingDetail?infoDATA=${encodeURIComponent(JSON.stringify({startDept:this.queryObj.startDeptId,uuid:this.queryObj.gdId}))}&id=${this.queryObj.signDeptId}&t=big&gdState=${this.queryObj.gdState}`
257
+        })
258
+      },
251 259
       // 手动查询药品-确认
252 260
       drugbagOk(data) {
253 261
         console.log(data);
@@ -373,9 +381,9 @@
373 381
                 //标本和标本轮巡工单,扫描标本后会自动调用摄像头,继续扫描,直到status不是200
374 382
                 if (this.type == "specimenPlan" || this.type == "specimen") {
375 383
                   if (type === 'scan') {
376
-                    setTimeout(()=>{
384
+                    setTimeout(() => {
377 385
                       this.Scanning_again();
378
-                    },500)
386
+                    }, 500)
379 387
                   }
380 388
                 }
381 389
                 this.speNum = ress.specimenCount;
@@ -803,5 +811,31 @@
803 811
         margin-top: 16rpx;
804 812
       }
805 813
     }
814
+
815
+    .foot_btn_spe {
816
+      line-height: 88rpx;
817
+      height: 100rpx;
818
+      margin-top: 40rpx;
819
+      text-align: center;
820
+      display: flex;
821
+      justify-content: space-between;
822
+      flex-wrap: wrap;
823
+
824
+      &::after {
825
+        content: '';
826
+        flex: 1;
827
+      }
828
+
829
+      view {
830
+        height: 88rpx;
831
+        width: 48%;
832
+        margin: 0 1%;
833
+        background-image: linear-gradient(to right, #72c172, #3bb197);
834
+        color: #fff;
835
+        border-radius: 8rpx;
836
+        font-size: 32rpx;
837
+        margin-top: 16rpx;
838
+      }
839
+    }
806 840
   }
807 841
 </style>

+ 32 - 16
pages/shortcutbuildOrders/shortcutbuildOrders.vue

@@ -62,24 +62,40 @@
62 62
     methods: {
63 63
       // 新建工单并签到
64 64
       createOrder() {
65
-        get(`/workerOrder/createQuickOrder/${this.msg.id}`, {}).then((res) => {
66
-          console.log(res)
67
-          if (res.status == 200) {
68
-            if (res.type === 'plan-spe-ddd-2') {
69
-              //需要扫描标本
70
-              uni.navigateTo({
71
-                url: `../../pages/scanning_code/scanning_code?type=${res.associationTypeName}&type1=${res.type}&id=${res.id}&deptCode=${res.deptCode}&dept=${res.deptName}&accountObj=undefined`,
72
-              });
73
-            } else {
74
-              uni.navigateTo({
75
-                url: "../receiptpage/receiptpage",
65
+        uni.showModal({
66
+          title: '提示',
67
+          content: "您确认建单吗?",
68
+          success: (res) => {
69
+            if (res.confirm) {
70
+              console.log('用户点击确定');
71
+              uni.showLoading({
72
+                mask: true,
73
+                title: '加载中'
74
+              })
75
+              get(`/workerOrder/createQuickOrder/${this.msg.id}`, {}).then((res) => {
76
+                console.log(res)
77
+                uni.hideLoading();
78
+                if (res.status == 200) {
79
+                  if (res.type === 'plan-spe-ddd-2') {
80
+                    //需要扫描标本
81
+                    uni.navigateTo({
82
+                      url: `../../pages/scanning_code/scanning_code?type=${res.associationTypeName}&type1=${res.type}&id=${res.id}&deptCode=${res.deptCode}&dept=${res.deptName}&accountObj=undefined`,
83
+                    });
84
+                  } else {
85
+                    uni.navigateTo({
86
+                      url: "../receiptpage/receiptpage",
87
+                    });
88
+                  }
89
+                } else {
90
+                  uni.showToast({
91
+                    icon: "none",
92
+                    title: "请求失败!",
93
+                  });
94
+                }
76 95
               });
96
+            } else if (res.cancel) {
97
+              console.log('用户点击取消');
77 98
             }
78
-          } else {
79
-            uni.showToast({
80
-              icon: "none",
81
-              title: "请求失败!",
82
-            });
83 99
           }
84 100
         });
85 101
       },

+ 74 - 23
pages/specimenChecking/specimenChecking.vue

@@ -1,7 +1,7 @@
1 1
 <template>
2
-  <view class="Receipt_infopage">
2
+  <view class="specimenChecking">
3 3
     <view class="title">请您确认一下科室标本数量!</view>
4
-    <view class="page_item_wrap" v-for="item in msg.deptDataList" :key="item[0]">
4
+    <view class="page_item_wrap" v-for="item in list" :key="item[0]" @click="gotoDetail(item)">
5 5
       <view class="page_item">
6 6
         <view class="page_item_top">
7 7
           <view class="page_item_top-inner">
@@ -38,42 +38,89 @@
38 38
 <script>
39 39
   import {
40 40
     get,
41
+    post,
41 42
     webHandle
42 43
   } from "../../http/http.js";
43 44
   export default {
44 45
     data() {
45 46
       return {
47
+        list: [],
46 48
         msg: {}, //页面展示信息
47
-        targetDeptShow: [], //目标科室
48 49
       };
49 50
     },
50 51
     methods: {
52
+      // 获取列表
53
+      getList() {
54
+        uni.showLoading({
55
+          mask: true,
56
+          title: '加载中'
57
+        })
58
+        let postData = {
59
+          startDept: this.msg.startDept,
60
+          targetDept: this.msg.targetDept,
61
+          uuid: this.msg.uuid
62
+        }; //起点科室id,选择的科室ids
63
+        post(`/api/getDeptSpecimensNum`, postData).then((res) => {
64
+          uni.hideLoading();
65
+          uni.stopPullDownRefresh();
66
+          if (res.status == 200) {
67
+            this.list = res.data;
68
+          } else {
69
+            uni.showToast({
70
+              icon: "none",
71
+              title: "请求失败!",
72
+            });
73
+          }
74
+        });
75
+      },
76
+      // 跳转到详情页
77
+      gotoDetail(item) {
78
+        uni.navigateTo({
79
+          url: `../../pages/specimenCheckingDetail/specimenCheckingDetail?infoDATA=${encodeURIComponent(JSON.stringify(this.msg))}&id=${item[0]}&endDepts=${this.msg.targetDept}`,
80
+        });
81
+      },
51 82
       // 知道了
52 83
       goto() {
53 84
         uni.navigateTo({
54 85
           url: `../../pages/receiptpage/receiptpage`,
55 86
         });
56 87
       },
57
-      // 新建工单并签到
88
+      // 确认数量并建单
58 89
       createOrder() {
59
-        get(`/workerOrder/createQuickOrder/${this.msg.id}`, {}).then((res) => {
60
-          console.log(res)
61
-          if (res.status == 200) {
62
-            if (res.type === 'plan-spe-ddd-2') {
63
-              //需要扫描标本
64
-              uni.navigateTo({
65
-                url: `../../pages/scanning_code/scanning_code?type=${res.associationTypeName}&type1=${res.type}&id=${res.id}&deptCode=${res.deptCode}&dept=${res.deptName}&accountObj=undefined`,
66
-              });
67
-            } else {
68
-              uni.navigateTo({
69
-                url: "../receiptpage/receiptpage",
90
+        uni.showModal({
91
+          title: '提示',
92
+          content: "您确认建单吗?",
93
+          success: (res) => {
94
+            if (res.confirm) {
95
+              console.log('用户点击确定');
96
+              uni.showLoading({
97
+                mask: true,
98
+                title: '加载中'
99
+              })
100
+              get(`/workerOrder/createQuickOrder/${this.msg.id}`, {}).then((res) => {
101
+                console.log(res)
102
+                uni.hideLoading();
103
+                if (res.status == 200) {
104
+                  if (res.type === 'plan-spe-ddd-2') {
105
+                    //需要扫描标本
106
+                    uni.navigateTo({
107
+                      url: `../../pages/scanning_code/scanning_code?type=${res.associationTypeName}&type1=${res.type}&id=${res.id}&deptCode=${res.deptCode}&dept=${res.deptName}&accountObj=undefined&endDepts=${this.msg.targetDept}`,
108
+                    });
109
+                  } else {
110
+                    uni.navigateTo({
111
+                      url: "../receiptpage/receiptpage",
112
+                    });
113
+                  }
114
+                } else {
115
+                  uni.showToast({
116
+                    icon: "none",
117
+                    title: "请求失败!",
118
+                  });
119
+                }
70 120
               });
121
+            } else if (res.cancel) {
122
+              console.log('用户点击取消');
71 123
             }
72
-          } else {
73
-            uni.showToast({
74
-              icon: "none",
75
-              title: "请求失败!",
76
-            });
77 124
           }
78 125
         });
79 126
       },
@@ -81,7 +128,7 @@
81 128
     onLoad(options) {
82 129
       console.log(options, "快捷建单");
83 130
       this.msg = JSON.parse(options.infoDATA);
84
-      this.targetDeptShow = this.msg.targetDeptShow.split(",");
131
+      this.getList();
85 132
       // #ifdef APP-PLUS
86 133
       webHandle("no", "app");
87 134
       // #endif
@@ -89,11 +136,15 @@
89 136
       webHandle("no", "wx");
90 137
       // #endif
91 138
     },
139
+    onPullDownRefresh() {
140
+      this.getList();
141
+    },
92 142
   };
93 143
 </script>
94
-<style lang="less">
95
-  .Receipt_infopage {
144
+<style lang="less" scoped>
145
+  .specimenChecking {
96 146
     padding-bottom: 100rpx;
147
+
97 148
     .title {
98 149
       font-size: 48rpx;
99 150
       margin-top: 24rpx;

+ 963 - 0
pages/specimenCheckingDetail/specimenCheckingDetail.vue

@@ -0,0 +1,963 @@
1
+<template>
2
+  <view class="specimenCheckingDetail">
3
+    <view class="page_header" v-if="options.t && (modifyReason || imgs.length)">
4
+      <view class="page_header_item" v-if="modifyReason">
5
+        <view class="page_header_title"> 修改原因: </view>
6
+        <view class="page_header_content">
7
+          {{ modifyReason }}
8
+        </view>
9
+      </view>
10
+      <view class="page_header_item" v-if="imgs.length">
11
+        <view class="page_header_title"> 图片列表: </view>
12
+        <view class="page_header_content">
13
+          <image
14
+            v-for="(item, i) in imgs"
15
+            :key="i"
16
+            :src="item"
17
+            @click="previewImage(i)"
18
+            mode="widthFix"
19
+            @error="close(i)"
20
+          ></image>
21
+        </view>
22
+      </view>
23
+    </view>
24
+    <view class="page_item_wrap" v-for="item in list" :key="item.id">
25
+      <view class="page_item">
26
+        <view class="page_item_top">
27
+          <view class="page_item_top-inner">
28
+            <view class="page_item_top_L">
29
+              <view class="L_text">{{ item.patientName }}</view>
30
+            </view>
31
+            <view class="page_item_top_R">
32
+              <view class="L_iocn"
33
+                ><button
34
+                  type="primary"
35
+                  size="mini"
36
+                  class="back"
37
+                  @click="back(item, msg.uuid)"
38
+                >
39
+                  退回
40
+                </button></view
41
+              >
42
+            </view>
43
+          </view>
44
+        </view>
45
+        <view class="page_item_cont">
46
+          <view class="page_item_cont_T">
47
+            <view class="page_item_cont_title">
48
+              <view> 检验项目 </view>
49
+              <view class="text_big">{{ item.specimenDesc || "无" }}</view>
50
+            </view>
51
+            <view class="page_item_cont_title">
52
+              <view> 标本编码 </view>
53
+              <view class="text_big">{{ item.scode || "无" }}</view>
54
+            </view>
55
+            <view class="page_item_cont_title">
56
+              <view> 标本类型 </view>
57
+              <view class="text_big">{{
58
+                item.stype ? item.stype.name : "无"
59
+              }}</view>
60
+            </view>
61
+            <view class="page_item_cont_title">
62
+              <view> 申请科室 </view>
63
+              <view class="text_big">{{
64
+                item.sickRoom ? item.sickRoom.dept : "无"
65
+              }}</view>
66
+            </view>
67
+            <view class="page_item_cont_title">
68
+              <view> 住院号 </view>
69
+              <view class="text_big">{{ item.residenceNo || "无" }}</view>
70
+            </view>
71
+          </view>
72
+        </view>
73
+        <view class="L"></view>
74
+        <view class="R"></view>
75
+      </view>
76
+      <view class="L-l"></view>
77
+      <view class="R-l"></view>
78
+    </view>
79
+    <view class="foot_btn2">
80
+      <view class="btn2" @click="showChangeSpe()">修改数量</view>
81
+      <view class="btn2" @click="goto()">返回</view>
82
+    </view>
83
+    <!-- 修改标本数量弹窗 -->
84
+    <changeSpeNum
85
+      v-if="changeSpeModels.disjunctor"
86
+      :title="changeSpeModels.title"
87
+      :disjunctor="changeSpeModels.disjunctor"
88
+      @ok="speOk"
89
+      @cancel="speCancel"
90
+      :num="speNum"
91
+    >
92
+    </changeSpeNum>
93
+    <!-- 退回弹窗 -->
94
+    <backModel
95
+      v-if="backModels.disjunctor"
96
+      :title="backModels.title"
97
+      :disjunctor="backModels.disjunctor"
98
+      @ok="backOk"
99
+      @cancel="backCancel"
100
+    ></backModel>
101
+    <!-- 填写交接人账号弹窗 -->
102
+    <selectAccount
103
+      v-if="hosModels.disjunctor"
104
+      :title="hosModels.title"
105
+      :disjunctor="hosModels.disjunctor"
106
+      @ok="hosOk"
107
+      @cancel="hosCancel"
108
+    >
109
+    </selectAccount>
110
+    <!-- 弹窗 -->
111
+    <showModel
112
+      :title="models.title"
113
+      :icon="models.icon"
114
+      :disjunctor="models.disjunctor"
115
+      :content="models.content"
116
+      :operate="models.operate"
117
+      @know="know"
118
+    ></showModel>
119
+  </view>
120
+</template>
121
+<script>
122
+import { get, post, webHandle } from "../../http/http.js";
123
+export default {
124
+  data() {
125
+    return {
126
+      res: {},
127
+      backStatus: "",
128
+      workOrderId: 0,
129
+      backSpecimen: {},
130
+      backParams: {},
131
+      imgs: [],
132
+      // --------------------
133
+      speNum: 0,
134
+      modifyReason: "",
135
+      options: {},
136
+      selectDeptId: null,
137
+      msg: {}, //传递的信息
138
+      list: [],
139
+      targetDeptShow: [], //目标科室
140
+      // 修改标本数量弹窗model
141
+      changeSpeModels: {
142
+        disjunctor: false,
143
+      },
144
+      // 退回弹窗model
145
+      backModels: {
146
+        disjunctor: false,
147
+      },
148
+      // 填写交接人账号弹窗model
149
+      hosModels: {
150
+        disjunctor: false,
151
+      },
152
+      // 弹窗model
153
+      models: {
154
+        disjunctor: false,
155
+      },
156
+    };
157
+  },
158
+  methods: {
159
+    close(i) {
160
+      this.imgs.splice(i, 1);
161
+    },
162
+    know() {
163
+      this.models.disjunctor = false;
164
+      if (this.models.icon === "success") {
165
+        uni.navigateTo({
166
+          url: "../receiptpage/receiptpage",
167
+        });
168
+      }
169
+    },
170
+    // 退回
171
+    back(specimen, workOrderId) {
172
+      this.backSpecimen = specimen;
173
+      this.backStatus = "back";
174
+      this.workOrderId = workOrderId;
175
+      this.showBack();
176
+    },
177
+    // 退回
178
+    backHandler(specimen, workorderId, data) {
179
+      console.log(specimen);
180
+      const { reasonForReturn, remarks } = this.backParams;
181
+      uni.showLoading({
182
+        title: "加载中",
183
+        mask: true,
184
+      });
185
+      let postData = {
186
+        deptId:
187
+          this.selectDeptId == "undefined"
188
+            ? this.msg.startDept
189
+            : this.selectDeptId,
190
+        reasonForReturn,
191
+        remarks,
192
+        scode: specimen.scode,
193
+        hosId: uni.getStorageSync("userData").user.currentHospital.id,
194
+        speState: specimen.speState ? specimen.speState.id : undefined,
195
+        handoverId: data ? data.accountId : undefined,
196
+        handoverName: data ? data.accountName : undefined,
197
+        gdId: workorderId || undefined,
198
+      };
199
+      post("/workerOrder/returnSpecimen", postData).then((res) => {
200
+        uni.hideLoading();
201
+        if (res.state == 200) {
202
+          this.models = {
203
+            disjunctor: true,
204
+            title: "提示",
205
+            content: `标本退回成功`,
206
+            icon: "success",
207
+          };
208
+        } else {
209
+          this.models = {
210
+            disjunctor: true,
211
+            title: "提示",
212
+            content: `标本退回失败`,
213
+            icon: "error",
214
+          };
215
+        }
216
+      });
217
+    },
218
+    // 填写交接人账号-确认
219
+    hosOk(data) {
220
+      console.log(data);
221
+      const { accountName, account, accountId } = data;
222
+      if (!accountName && !account) {
223
+        //没有填写交接人
224
+        uni.showModal({
225
+          title: "提示",
226
+          content: "请填写交接人账号!",
227
+          showCancel: false,
228
+          success: function (res) {
229
+            if (res.confirm) {
230
+              console.log("用户点击确定");
231
+            } else if (res.cancel) {
232
+              console.log("用户点击取消");
233
+            }
234
+          },
235
+        });
236
+        return;
237
+      } else if ((!accountName && account) || (accountName && !account)) {
238
+        //没有填写交接人
239
+        uni.showModal({
240
+          title: "提示",
241
+          content: "请填写正确的交接人账号!",
242
+          showCancel: false,
243
+          success: function (res) {
244
+            if (res.confirm) {
245
+              console.log("用户点击确定");
246
+            } else if (res.cancel) {
247
+              console.log("用户点击取消");
248
+            }
249
+          },
250
+        });
251
+        return;
252
+      }
253
+      this.hosModels.disjunctor = false;
254
+      uni.showLoading({
255
+        title: "加载中",
256
+        mask: true,
257
+      });
258
+      console.log(this.backStatus, "this.backStatus");
259
+      if ((this.backStatus = "back")) {
260
+        // 退回
261
+        this.backHandler(this.backSpecimen, this.msg.uuid, data);
262
+      }
263
+    },
264
+    // 填写交接人账号-取消
265
+    hosCancel() {
266
+      this.hosModels.disjunctor = false;
267
+    },
268
+    // 填写交接人账号弹窗
269
+    showSelectAccount() {
270
+      this.hosModels = {
271
+        title: "填写交接人账号",
272
+        disjunctor: true,
273
+      };
274
+    },
275
+    // 退回-确认
276
+    backOk(data) {
277
+      console.log(data);
278
+      this.backParams = data;
279
+      this.hosModels.disjunctor = false;
280
+      let postData = {
281
+        idx: 0,
282
+        sum: 1,
283
+        hospitalConfig: {
284
+          hosId: uni.getStorageSync("userData").user.currentHospital.id,
285
+          key: "returnSpecimenWhetherHandover",
286
+        },
287
+      };
288
+      uni.showLoading({
289
+        title: "加载中",
290
+        mask: true,
291
+      });
292
+      post("/simple/data/fetchDataList/hospitalConfig", postData).then(
293
+        (result) => {
294
+          uni.hideLoading();
295
+          if (result.status == 200) {
296
+            if (result.list[0].value == 1) {
297
+              this.showSelectAccount();
298
+            } else {
299
+              this.backHandler(this.backSpecimen, this.workOrderId);
300
+            }
301
+          } else {
302
+            uni.showToast({
303
+              icon: "none",
304
+              title: "请求失败!",
305
+            });
306
+          }
307
+        }
308
+      );
309
+    },
310
+    // 退回-取消
311
+    backCancel() {
312
+      this.backModels.disjunctor = false;
313
+    },
314
+    // 退回弹窗
315
+    showBack() {
316
+      this.backModels = {
317
+        title: "退回",
318
+        disjunctor: true,
319
+      };
320
+    },
321
+    previewImage(index) {
322
+      //uniapp预览轮播图
323
+      uni.previewImage({
324
+        current: index, //预览图片的下标
325
+        urls: this.imgs, //预览图片的地址,必须要数组形式,如果不是数组形式就转换成数组形式就可以
326
+      });
327
+    },
328
+    // ---------------------------
329
+    getInfo() {
330
+      uni.showLoading({
331
+        mask: true,
332
+        title: "加载中",
333
+      });
334
+      let postData = {
335
+        deptId:
336
+          this.selectDeptId == "undefined"
337
+            ? this.msg.startDept
338
+            : this.selectDeptId,
339
+        gdId: this.msg.uuid,
340
+      };
341
+      post(`/api/getStartDeptSpecimensNum`, postData).then((res) => {
342
+        uni.hideLoading();
343
+        if (res.status == 200) {
344
+          this.speNum = res.deptSpecimensNum;
345
+          this.modifyReason = res.modifyReason;
346
+          get(
347
+            `/common/common/listAttachment/specimenPhotos/${res.bindId}`
348
+          ).then((result) => {
349
+            if (result.status == 200) {
350
+              this.imgs = result.data.map((v) => v.previewUrl);
351
+            } else {
352
+              this.imgs = [];
353
+            }
354
+          });
355
+        } else {
356
+          this.speNum = "";
357
+          this.modifyReason = "";
358
+        }
359
+      });
360
+    },
361
+    getList() {
362
+      uni.showLoading({
363
+        mask: true,
364
+        title: "加载中",
365
+      });
366
+      let postData = {
367
+        checkDept: this.options.endDepts, //终点科室
368
+        transDept: Number(this.msg.startDept), //起点科室id
369
+      };
370
+      if (this.selectDeptId != "undefined") {
371
+        if (Number(this.msg.startDept) != Number(this.selectDeptId)) {
372
+          postData.checkDept = Number(this.selectDeptId); //签到的科室或者选择的科室
373
+        }
374
+      }
375
+      post(`/api/getTransDeptSpecimens`, postData).then((res) => {
376
+        uni.hideLoading();
377
+        uni.stopPullDownRefresh();
378
+        if (res.status == 200) {
379
+          this.list = res.data;
380
+          this.getInfo();
381
+        } else {
382
+          uni.showToast({
383
+            icon: "none",
384
+            title: "请求失败!",
385
+          });
386
+        }
387
+      });
388
+    },
389
+    // 返回
390
+    goto() {
391
+      if (this.options.t == "big") {
392
+        uni.navigateBack();
393
+      } else if (this.options.t == "small") {
394
+        uni.navigateBack();
395
+      } else {
396
+        uni.navigateTo({
397
+          url: `../../pages/specimenChecking/specimenChecking?infoDATA=${encodeURIComponent(
398
+            JSON.stringify(this.msg)
399
+          )}`,
400
+        });
401
+      }
402
+    },
403
+    // 修改标本数量-确认
404
+    speOk(data) {
405
+      console.log(data);
406
+      const pathUrl = uni.getStorageSync("path");
407
+      const { speNum, reason, imageValue } = data;
408
+      this.changeSpeModels.disjunctor = false;
409
+      uni.showLoading({
410
+        mask: true,
411
+        title: "加载中",
412
+      });
413
+      let postData = {
414
+        checkDept: this.options.endDepts, //终点科室
415
+        transDeptId: this.msg.startDept,
416
+        gdId: this.msg.uuid,
417
+        deptId:
418
+          this.selectDeptId == "undefined"
419
+            ? this.msg.startDept
420
+            : this.selectDeptId,
421
+        specimensNum: speNum,
422
+        modifyReason: reason,
423
+      };
424
+      post("/api/updateCheckDeptSpecimensNum", postData).then((res) => {
425
+        if (res.status == 200) {
426
+          console.log(imageValue);
427
+          if (!imageValue.length) {
428
+            uni.hideLoading();
429
+            uni.showModal({
430
+              title: "提示",
431
+              content: "修改成功!",
432
+              showCancel: false,
433
+              success: (result) => {
434
+                if (result.confirm) {
435
+                  console.log("用户点击确定");
436
+                  if (this.options.t == "big") {
437
+                    if (this.options.gdState == 4) {
438
+                      // 待到达
439
+                      uni.navigateTo({
440
+                        url: `../../pages/receiptpage/receiptpage`,
441
+                      });
442
+                    } else if (this.options.gdState == 5) {
443
+                      // 待送达
444
+                      if (res.type1 === "plan-spe-ddd-2") {
445
+                      } else {
446
+                        let content = `本工单已签到<strong class="red">${
447
+                          res.scanSet ? res.scanSet.join("、") : ""
448
+                        }</strong>,剩余需签到科室<strong class="red">${
449
+                          res.notScanSet ? res.notScanSet.join("、") : ""
450
+                        }</strong>,总签收<strong class="red">${
451
+                          res.totalAcceptance
452
+                        }</strong>只,剩余<strong class="red">${
453
+                          res.notAcceptance
454
+                        }</strong>只未签收,您确定完成工单吗?`;
455
+                        uni.navigateTo({
456
+                          url: `../scanning/scanning?type=${res.type}&type1=${
457
+                            res.type1
458
+                          }&id=${encodeURIComponent(
459
+                            JSON.stringify([res.gdid])
460
+                          )}&content=${content}`,
461
+                        });
462
+                      }
463
+                    }
464
+                  } else if (this.options.t == "small") {
465
+                    if (this.selectDeptId == "undefined") {
466
+                      //快捷建单建单进入
467
+                      uni.navigateTo({
468
+                        url: `../../pages/receiptpage/receiptpage`,
469
+                      });
470
+                    } else {
471
+                      if (this.options.gdState == 4) {
472
+                        // 待到达
473
+                        uni.navigateTo({
474
+                          url: `../../pages/receiptpage/receiptpage`,
475
+                        });
476
+                      } else if (this.options.gdState == 5) {
477
+                        // 待送达
478
+                        if (res.type1 === "plan-spe-ddd-2") {
479
+                        } else {
480
+                          let content = `本工单已签到<strong class="red">${
481
+                            res.scanSet ? res.scanSet.join("、") : ""
482
+                          }</strong>,剩余需签到科室<strong class="red">${
483
+                            res.notScanSet ? res.notScanSet.join("、") : ""
484
+                          }</strong>,总签收<strong class="red">${
485
+                            res.totalAcceptance
486
+                          }</strong>只,剩余<strong class="red">${
487
+                            res.notAcceptance
488
+                          }</strong>只未签收,您确定完成工单吗?`;
489
+                          uni.navigateTo({
490
+                            url: `../scanning/scanning?type=${res.type}&type1=${
491
+                              res.type1
492
+                            }&id=${encodeURIComponent(
493
+                              JSON.stringify([res.gdid])
494
+                            )}&content=${content}`,
495
+                          });
496
+                        }
497
+                      }
498
+                    }
499
+                  } else {
500
+                    uni.navigateTo({
501
+                      url: `../../pages/specimenChecking/specimenChecking?infoDATA=${encodeURIComponent(
502
+                        JSON.stringify(this.msg)
503
+                      )}`,
504
+                    });
505
+                  }
506
+                } else if (result.cancel) {
507
+                  console.log("用户点击取消");
508
+                }
509
+              },
510
+            });
511
+            return;
512
+          }
513
+          let n = 0;
514
+          imageValue.forEach((v) => {
515
+            // 图片上传 start
516
+            console.log("压缩前");
517
+            let canvasWidth = v.image.width; //图片原始长宽
518
+            let canvasHeight = v.image.height;
519
+            let img = new Image();
520
+            img.src = v.path;
521
+            let canvas = document.createElement("canvas");
522
+            let ctx = canvas.getContext("2d");
523
+            canvas.width = canvasWidth;
524
+            canvas.height = canvasHeight;
525
+            ctx.drawImage(img, 0, 0, canvasWidth, canvasHeight);
526
+            canvas.toBlob(
527
+              (fileSrc) => {
528
+                let tp = window.URL.createObjectURL(fileSrc);
529
+                console.log("压缩后");
530
+                n++;
531
+                uni.uploadFile({
532
+                  url:
533
+                    pathUrl +
534
+                    "/common/common/uploadAttachment/specimenPhotos/" +
535
+                    res.deptSpecimensNumId +
536
+                    "/666",
537
+                  filePath: tp,
538
+                  name: "file",
539
+                  formData: {
540
+                    filename: v.cloudPath,
541
+                  },
542
+                  success: (uploadFileRes) => {
543
+                    console.log(uploadFileRes);
544
+                    if (--n === 0) {
545
+                      uni.hideLoading();
546
+                      uni.showModal({
547
+                        title: "提示",
548
+                        content: "修改成功!",
549
+                        showCancel: false,
550
+                        success: (res) => {
551
+                          if (res.confirm) {
552
+                            console.log("用户点击确定", this.options.t);
553
+                            if (this.options.t == "big") {
554
+                              if (this.options.gdState == 4) {
555
+                                // 待到达
556
+                                uni.navigateTo({
557
+                                  url: `../../pages/receiptpage/receiptpage`,
558
+                                });
559
+                              } else if (this.options.gdState == 5) {
560
+                                // 待送达
561
+                                uni.navigateTo({
562
+                                  url: `../../pages/receiptpage/receiptpage`,
563
+                                });
564
+                              }
565
+                            } else if (this.options.t == "small") {
566
+                              if (this.selectDeptId == "undefined") {
567
+                                //快捷建单建单进入
568
+                                uni.navigateTo({
569
+                                  url: `../../pages/receiptpage/receiptpage`,
570
+                                });
571
+                              } else {
572
+                                if (this.options.gdState == 4) {
573
+                                  // 待到达
574
+                                  uni.navigateTo({
575
+                                    url: `../../pages/receiptpage/receiptpage`,
576
+                                  });
577
+                                } else if (this.options.gdState == 5) {
578
+                                  // 待送达
579
+                                  uni.navigateTo({
580
+                                    url: `../../pages/receiptpage/receiptpage`,
581
+                                  });
582
+                                }
583
+                              }
584
+                            } else {
585
+                              uni.navigateTo({
586
+                                url: `../../pages/specimenChecking/specimenChecking?infoDATA=${encodeURIComponent(
587
+                                  JSON.stringify(this.msg)
588
+                                )}`,
589
+                              });
590
+                            }
591
+                          } else if (res.cancel) {
592
+                            console.log("用户点击取消");
593
+                          }
594
+                        },
595
+                      });
596
+                    }
597
+                  },
598
+                  fail: (err) => {
599
+                    n--;
600
+                    console.error(err);
601
+                    uni.hideLoading();
602
+                    uni.showToast({
603
+                      icon: "none",
604
+                      title: "上传失败",
605
+                      duration: 2000,
606
+                    });
607
+                  },
608
+                });
609
+              },
610
+              "image/jpeg",
611
+              0.3
612
+            );
613
+            // 图片上传 end
614
+          });
615
+        } else {
616
+          uni.hideLoading();
617
+          uni.showToast({
618
+            icon: "none",
619
+            title: "请求失败!",
620
+          });
621
+        }
622
+      });
623
+    },
624
+    // 修改标本数量-取消
625
+    speCancel() {
626
+      this.changeSpeModels.disjunctor = false;
627
+    },
628
+    // 修改标本数量弹窗
629
+    showChangeSpe() {
630
+      this.changeSpeModels = {
631
+        title: "修改标本数量",
632
+        disjunctor: true,
633
+      };
634
+    },
635
+  },
636
+  onLoad(options) {
637
+    console.log(options, "快捷建单");
638
+    this.options = options;
639
+    this.msg = JSON.parse(options.infoDATA);
640
+    this.selectDeptId = options.id;
641
+    // this.msg = JSON.parse(options.infoDATA);
642
+    // this.targetDeptShow = this.msg.targetDeptShow.split(",");
643
+    this.getList();
644
+    // #ifdef APP-PLUS
645
+    webHandle("no", "app");
646
+    // #endif
647
+    // #ifdef H5
648
+    webHandle("no", "wx");
649
+    // #endif
650
+  },
651
+  onPullDownRefresh() {
652
+    this.getList();
653
+  },
654
+};
655
+</script>
656
+<style lang="less" scoped>
657
+.specimenCheckingDetail {
658
+  padding-bottom: 100rpx;
659
+
660
+  .page_header {
661
+    margin: 20rpx;
662
+    padding: 16rpx;
663
+    border: 2rpx solid #e5e9ed;
664
+    background: #fff;
665
+    border-radius: 8rpx;
666
+
667
+    .page_header_item {
668
+      margin-bottom: 16rpx;
669
+
670
+      .page_header_title {
671
+        margin-bottom: 8rpx;
672
+        font-weight: bold;
673
+      }
674
+
675
+      .page_header_content {
676
+        display: flex;
677
+
678
+        image {
679
+          height: 100rpx;
680
+          width: 30%;
681
+          margin: 0 8rpx;
682
+        }
683
+      }
684
+    }
685
+  }
686
+
687
+  .page_item_wrap {
688
+    width: 100%;
689
+    height: auto;
690
+    box-sizing: border-box;
691
+    position: relative;
692
+    margin-bottom: 16rpx;
693
+
694
+    .page_item {
695
+      margin-top: 16rpx;
696
+      margin-bottom: 124rpx;
697
+      background: #fff;
698
+      border-radius: 8rpx;
699
+      margin: 0 20rpx;
700
+      border: 2rpx solid #e5e9ed;
701
+      position: relative;
702
+      overflow: hidden;
703
+      padding: 0 16rpx;
704
+
705
+      .L {
706
+        width: 40rpx;
707
+        height: 40rpx;
708
+        border-radius: 50%;
709
+        background: #f9fafb;
710
+        position: absolute;
711
+        left: -20rpx;
712
+        top: 68rpx;
713
+        border: 2rpx solid #e5e9ed;
714
+      }
715
+
716
+      .R {
717
+        width: 40rpx;
718
+        height: 40rpx;
719
+        border-radius: 50%;
720
+        background: #f9fafb;
721
+        position: absolute;
722
+        float: right;
723
+        right: -20rpx;
724
+        top: 68rpx;
725
+        border: 2rpx solid #e5e9ed;
726
+      }
727
+
728
+      .starting {
729
+        width: 50rpx;
730
+        height: 50rpx;
731
+        color: #fff;
732
+        background: #49b856;
733
+        display: inline-block;
734
+        border-radius: 50%;
735
+        text-align: center;
736
+        line-height: 46rpx;
737
+        font-size: 32rpx;
738
+        margin-right: 6rpx;
739
+      }
740
+
741
+      .End {
742
+        width: 50rpx;
743
+        height: 50rpx;
744
+        color: #fff;
745
+        background: #39b199;
746
+        display: inline-block;
747
+        border-radius: 50%;
748
+        text-align: center;
749
+        line-height: 46rpx;
750
+        font-size: 32rpx;
751
+        margin-right: 6rpx;
752
+      }
753
+
754
+      .page_item_top {
755
+        height: 88rpx;
756
+        border-bottom: 2rpx dashed #e5e9ed;
757
+        padding: 0 16rpx;
758
+
759
+        .page_item_top-inner {
760
+          display: flex;
761
+          justify-content: space-between;
762
+          align-items: center;
763
+          height: 100%;
764
+
765
+          .page_item_top_L {
766
+            .emergencys {
767
+              background: #ff3b53 !important;
768
+              width: 124rpx !important;
769
+            }
770
+
771
+            .emergency {
772
+              background: #ff3b53 !important;
773
+            }
774
+
775
+            .emergency1 {
776
+              background: #49b856 !important;
777
+            }
778
+
779
+            .page_item_cont_start {
780
+              text-align: center;
781
+              height: 44rpx;
782
+              width: 104rpx;
783
+              line-height: 44rpx;
784
+              border-radius: 8rpx;
785
+              background: #49b856;
786
+              color: #fff;
787
+              display: inline-block;
788
+            }
789
+
790
+            .L_time {
791
+              color: #6cc076;
792
+              font-size: 32rpx;
793
+            }
794
+
795
+            .L_text {
796
+              font-size: 32rpx;
797
+              font-weight: 700;
798
+            }
799
+          }
800
+
801
+          .page_item_top_R {
802
+            font-size: 32rpx;
803
+
804
+            .back {
805
+              background-color: #49b856;
806
+            }
807
+
808
+            .L_iocn {
809
+              color: rgb(7, 134, 60);
810
+              font-size: 36rpx;
811
+              font-weight: 700;
812
+            }
813
+          }
814
+        }
815
+      }
816
+
817
+      .page_item_cont {
818
+        min-height: 90rpx;
819
+        padding: 0 16rpx;
820
+        text-align: left;
821
+        position: relative;
822
+
823
+        .text_big {
824
+          font-size: 32rpx;
825
+          font-weight: 700;
826
+          margin-top: 10rpx;
827
+
828
+          p {
829
+            font-weight: 700;
830
+            line-height: 1.5;
831
+          }
832
+        }
833
+
834
+        .page_item_cont_T {
835
+          padding-top: 28rpx;
836
+          padding-bottom: 28rpx;
837
+          font-size: 28rpx;
838
+
839
+          .page_item_cont_title {
840
+            height: 100%;
841
+            font-size: 32rpx;
842
+            display: flex;
843
+            justify-content: space-between;
844
+          }
845
+        }
846
+
847
+        .page_item_cont_B {
848
+          padding-top: 28rpx;
849
+          margin-bottom: 28rpx;
850
+
851
+          .page_item_cont_title {
852
+            font-size: 32rpx;
853
+            display: flex;
854
+            justify-content: space-between;
855
+          }
856
+
857
+          .page_item_cont_title1 {
858
+            height: 60rpx;
859
+            line-height: 60rpx;
860
+            font-size: 32rpx;
861
+            padding-left: 64rpx;
862
+          }
863
+        }
864
+      }
865
+
866
+      .page_item_foot {
867
+        border-top: 2rpx dashed #e5e9ed;
868
+        border-bottom: 2rpx dashed #e5e9ed;
869
+        padding: 28rpx 16rpx;
870
+        text-align: left;
871
+
872
+        .page_item_foot_text {
873
+          font-size: 32rpx;
874
+          margin-bottom: 20rpx;
875
+
876
+          .text1 {
877
+            color: rgb(102, 102, 102);
878
+          }
879
+
880
+          .text2 {
881
+            float: right;
882
+            font-weight: 700;
883
+          }
884
+        }
885
+      }
886
+
887
+      #infos {
888
+        display: none;
889
+      }
890
+
891
+      .page_item_infos {
892
+        padding-bottom: 20rpx;
893
+        border-bottom: 2rpx dashed #e5e9ed;
894
+
895
+        .page_item_info2 {
896
+          text-align: left;
897
+          line-height: 60rpx;
898
+          font-size: 32rpx;
899
+          padding-left: 16rpx;
900
+
901
+          .page_item_foot_text {
902
+            font-size: 32rpx;
903
+            margin-bottom: 20rpx;
904
+
905
+            .text1 {
906
+              color: rgb(102, 102, 102);
907
+            }
908
+
909
+            .text2 {
910
+              float: right;
911
+              font-weight: 700;
912
+            }
913
+          }
914
+        }
915
+      }
916
+    }
917
+
918
+    .L-l {
919
+      width: 2rpx;
920
+      height: 40rpx;
921
+      background: #f9fafb;
922
+      position: absolute;
923
+      left: 20rpx;
924
+      top: 72rpx;
925
+    }
926
+
927
+    .R-l {
928
+      width: 2rpx;
929
+      height: 40rpx;
930
+      background: #f9fafb;
931
+      position: absolute;
932
+      right: 20rpx;
933
+      top: 72rpx;
934
+    }
935
+  }
936
+
937
+  .foot_btn2 {
938
+    position: fixed;
939
+    bottom: 0;
940
+    width: 100vw;
941
+    padding: 0 20rpx;
942
+    box-sizing: border-box;
943
+    line-height: 66rpx;
944
+    height: 100rpx;
945
+    border-top: 2rpx solid #e5e9ed;
946
+    background: #f9fafb;
947
+    text-align: center;
948
+    display: flex;
949
+    justify-content: center;
950
+    align-items: center;
951
+
952
+    .btn2 {
953
+      height: 66rpx;
954
+      flex: 1;
955
+      margin: 16rpx 16rpx 0;
956
+      background-image: linear-gradient(to right, #72c172, #3bb197);
957
+      color: #fff;
958
+      border-radius: 8rpx;
959
+      font-size: 32rpx;
960
+    }
961
+  }
962
+}
963
+</style>