Przeglądaj źródła

feat(nurse): 新增护理打卡功能

- 添加护理打卡页面和相关 API
- 实现护理时间选择、图片上传和备注功能
- 添加护理记录列表展示功能
- 优化页面样式和交互
lzm 2 miesięcy temu
rodzic
commit
024c2ea9b6

+ 17 - 1
common/config/application-api.js

@@ -39,13 +39,29 @@ export const getCompanyNursesList = (data) => http.get('/dev-api/care/nurses/lis
 
 //图片上传
 export const uploadImg = (params, config = {}) => http.post(`/dev-api/care/clocks/upload`,params, config);
+export const uploadImgUrl = `/dev-api/care/clocks/upload`;
+
 
 //获取图片上传的数量
 export const getImgNumber = (data) => http.get(`/dev-api/system/workConfig/type/${data.key??'need_img_num'}`, data);
 
+
+// export const getClockList = (data) => http.get(`/dev-api/care/applications/clockList`, data);
+
+
 //添加护理打卡记录
 export const addCareClocks = (params, config = {}) => http.post(`/dev-api/care/clocks`, params, config);
 //修改护理打卡记录
 export const updateCareClocks = (params, config = {}) => http.put(`/dev-api/care/clocks`, params, config);
 //删除护理打卡记录
-export const delCareClocks = (data) => http.delete(`/dev-api/care/clocks/${data.id}`);
+export const delCareClocks = (data) => http.delete(`/dev-api/care/clocks/${data.id}`);
+
+//护理记录列表-护理人员
+//pageNum=1&pageSize=10&status=assigned
+export const getAppClockList = (data) => http.get(`/dev-api/care/applications/clockList`, data);
+//护理记录列表-护理公司
+//pageNumAssign=1&pageSizeAssign=10&status=wait_assign_nurse&pageNum=1
+export const getAssignList = (data) => http.get(`/dev-api/care/applications/assignList`, data);
+
+//得到当前护理打卡记录
+export const getClockList = (data) => http.get(`/dev-api/care/clocks/list`, data);

+ 14 - 0
pages.json

@@ -115,6 +115,20 @@
 					"navigationStyle": "custom",
 					"navigationBarTextStyle": "black"
 				}
+			},
+			{
+				"path": "pages/nurse/clockIn",
+				"style": {
+					"navigationStyle": "custom",
+					"navigationBarTitleText": "护理打卡-打卡表单"
+				}
+			},
+			{
+				"path": "pages/nurse/death",
+				"style": {
+					"navigationStyle": "custom",
+					"navigationBarTitleText": "护理打卡-死亡表单"
+				}
 			}
 		]
 	}],

+ 5 - 7
pages/subpack/pages/application/componenets/page1.vue

@@ -59,15 +59,13 @@
 	import {
 		ref,
 		reactive,
-		computed
+		computed,
+		onMounted,
+		onUnmounted
 	} from 'vue';
 	import {
 		useStore
 	} from 'vuex';
-	import {
-		onLoad,
-		onUnload
-	} from "@dcloudio/uni-app"
 	import {
 		postCareAssign,
 		postCareCheck,
@@ -179,14 +177,14 @@
 		})
 	}
 
-	onLoad(() => {
+	onMounted(() => {
 		uni.$on('choose', ({
 			checkList
 		}) => {
 			if (checkList && checkList.length > 0) chooseInfo.value = checkList[0];
 		})
 	})
-	onUnload(() => {
+	onUnmounted(() => {
 		uni.$off('choose')
 	})
 </script>

+ 178 - 139
pages/subpack/pages/application/componenets/page4.vue

@@ -1,28 +1,50 @@
 <template>
 	<view class="page4-warp">
-		<view class="page4-form">
-			<up-form labelPosition="top" :model="formData" :rules="formRule" ref="formRef">
-				<up-form-item label="护理时间" labelWidth="auto" labelPosition="left" required prop="nursingTime">
-					<up-input v-model="formData.nursingTime" disabled disabledColor="#ffffff" border="bottom"
-						placeholder="请选择打卡时间" @tap="showTime = true;" />
-				</up-form-item>
-				<up-form-item :label="`护理打卡(0/${imgNum})`" labelWidth="auto" prop="img" required>
-					<view class="flex-row justify-between align-center" style="width: 100%;">
-						<up-upload :fileList="fileList" multiple :sizeType="['compressed']" :capture="['camera']"
-							@afterRead="afterRead" @delete="deletePic" />
-					</view>
-				</up-form-item>
-				<up-form-item label="备注" labelWidth="auto">
-					<up-textarea v-model="formData.remark" placeholder="请输入您的打卡备注" count />
-				</up-form-item>
-			</up-form>
+		<view class="info-dot">打卡记录({{listTotal}}次)</view>
+		<view class="flow-list">
+			<up-steps current="2" direction="column">
+				<up-steps-item v-for="(flow, index) in listData" :key="index" class="position-relative"
+					:title="flow.nodeTitle">
+					<template #icon>
+						<view class="flow-icon"></view>
+					</template>
+					<template #desc>
+						<view class="flow-des">
+							<view class="flow-des-top">
+								<view> {{flow.createTime??' '}}</view>
+								<view :class="`flow-des-top-tips`">查看</view>
+							</view>
+							<view class="flow-des-bg">
+								<view v-if="flow.fileList.length>0">
+									<view>打卡图片({{flow.imgNum}}张):</view>
+									<view class="flow-des-img">
+										<up-image :src="item" :key="index1" v-for="(item, index1) in flow.fileList"
+											:width="'161rpx'" :height="'161rpx'" :mode="'aspectFill'"
+											:preview-src-list="flow.fileList" lazy-load
+											@error="imgErrorHandle(index, index1)">
+											<template #error>
+												<image src="@/pages/subpack/static/images/error-img.png"
+													style="width: 161rpx;height: 161rpx;" mode="aspectFill" />
+											</template>
+										</up-image>
+									</view>
+								</view>
+								<view :class="`flow-des-des`" v-if="flow.remark">
+									{{flow.remark}}
+								</view>
+							</view>
+						</view>
+					</template>
+				</up-steps-item>
+			</up-steps>
 		</view>
-
-		<u-datetime-picker :show="showTime" v-model="timeValue" mode="datetime" closeOnClickOverlay
-			@cancel="showTime = false" @close="showTime = false" @confirm="timeConfirm" />
 		<view class="btn-box">
 			<view class="flex-row ">
-				<up-button class="up-button" type="primary" @tap="checkTap">确定打卡</up-button>
+				<up-button class="up-button" type="error" style="width: 250rpx;" @tap="dieHandle">死亡</up-button>
+				<view class="btn-place"></view>
+				<up-button class="up-button" type="success" style="width: 250rpx;" @tap="endHandle">结束</up-button>
+        <view class="btn-place"></view>
+        <up-button class="up-button" type="primary"  @tap="clockHandle">‌打卡</up-button>
 			</view>
 		</view>
 	</view>
@@ -30,26 +52,23 @@
 
 <script setup>
 	import {
-		ref,
-		reactive,
-		computed,
-		onMounted
+		ref
 	} from 'vue';
 	import {
 		useStore
 	} from 'vuex';
 	import {
 		onLoad,
-		onUnload
 	} from "@dcloudio/uni-app"
 	import {
-		getImgNumber,
-		addCareClocks,
-		uploadImg
+		getClockList
 	} from '@/common/config/application-api.js'
+	import errorImage from '@/pages/subpack/static/images/error-img.png';
+
+	const listData = ref([]);
+	const listTotal = ref(0);
 
 
-	const store = useStore();
 	const props = defineProps({
 		item: {
 			type: Object,
@@ -59,139 +78,159 @@
 		}
 	})
 
-	const showTime = ref(false);
-	const timeValue = ref(new Date().getTime());
-	const formRef = ref(null);
-	const fileList = ref([]);
-	const formData = reactive({
-		img: [],
-		remark: '', //意见
-		nursingTime: '', //护理时间
-	})
-	const formRule = reactive({
-		nursingTime: [{
-			required: true,
-			message: '请选择护理时间',
-			trigger: ['blur', 'change']
-		}],
-		img: [{
-			required: true,
-			message: '请上传图片',
-			trigger: ['blur', 'change']
-		}]
-	})
-	//点击打卡
-	function checkTap() {
-		formRef.value.validate().then(res => {
-			if(res) uni.$u.toast('校验通过')
-			else uni.$u.toast('校验失败');
-		})
-	}
 
-	function timeConfirm(e) {
-		// console.log('timeConfirm=>', e);
-		timeValue.value = e.value;
-		formData.nursingTime = uni.$u.timeFormat(e.value, 'yyyy-mm-dd');
-		showTime.value = false;
-	}
-	//删除图片
-	function deletePic(event) {
-		fileList.value.splice(event.index, 1);
-	}
-	//新增图片
-	async function afterRead(event) {
-		// 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
-		let lists = [].concat(event.file);
-		let fileListLen = fileList.value.length;
-		lists.map((item) => {
-			fileList.value.push({
-				...item,
-				status: "uploading",
-				message: "上传中",
-			});
-		});
-		for (let i = 0; i < lists.length; i++) {
-			const result = await uploadFilePromise(lists[i].url);
-			let item = fileList.value[fileListLen];
-			fileList.value.splice(
-				fileListLen,
-				1,
-				Object.assign(item, {
-					status: "success",
-					message: "",
-					url: result,
-				})
-			);
-			fileListLen++;
+	function getList() {
+		if (!props.item.applyId) return false;
+		let params = {
+			pageNum: 1,
+			pageSize: 50,
+			applyId: props.item.applyId
 		}
+		getClockList({
+			params
+		}).then(data => {
+			//数组倒叙
+			listData.value = data.reverse();
+			listData.value.map(v => {
+				const imgs = v.imgPaths.split(",").filter(item => item.trim() !== "");
+				let fileList = []
+				imgs.forEach(function(item) {
+					let url = uni.$u.http.config.baseURL + '/dev-api/' + item;
+					fileList.push(url);
+				})
+				//截取前三张图片
+				v.fileList = fileList.slice(0, 3);
+			})
+			listTotal.value = data.length;
+		})
 	}
-/**
- * TODO 上传图片有问题,上传的时间是选择 还是当前时间 
- * 如果今天上传的护理记录  是否还可以继续上传 一天上传几次护理打卡记录
- */ 
-
-	//上传图片
-	function uploadFilePromise(url) {
-		return new Promise((resolve, reject) => {
-			let a = uni.uploadFile({
-				url: "http://127.0.0.1/dev-api/care/clocks/upload", // 仅为示例,非真实的接口地址
-				filePath: url,
-				name: "file",
-				formData: {
-					applyId: 12,
-				},
-				success: (res) => {
-					console.log('uploadImg=>', res);
-					resolve(res.data.data);
-				},
-			});
-			
-			/* uploadImg({
-				filePath: url,
-				name: 'file'
-			}).then(res => {
-				console.log('uploadImg=>', res);
-				resolve(res.data.data);
-			}) */
-		});
+
+	function imgErrorHandle(index, index1) {
+		listData.value[index].fileList[index1] = errorImage;
 	}
 
-	//获取打卡图片数量
-	const imgNum = ref(0);
+  // 死亡
+  function dieHandle() {
 
-	function getNumber() {
-		getImgNumber({
-			params: {
-				key: 'need_img_num'
-			}
-		}).then(res => {
-			imgNum.value = res.number;
-		})
+  }
+
+  //结束
+  function endHandle() {
+
+  }
+
+  //打卡
+  function clockHandle() {
+    uni.$u.route('/pages/subpack/pages/nurse/clockIn', {
+      id: props.item.applyId
+    })
+  }
+
+
+	function init() {
+		getList();
 	}
-	
-	onMounted(()=>{
-		getNumber();
-	})
+
+	init();
 </script>
 
 <style lang="scss" scoped>
-	.page4-warp {
-		padding: 30rpx;
+	.flow-icon {
+		width: 18rpx;
+		height: 18rpx;
+		border-radius: 50%;
+		background: #207DFF;
+	}
+
+	.info-dot {
+		position: relative;
+		margin: 20rpx;
+		padding-left: 20rpx;
+		font-size: 36rpx;
+		color: #0B0B0B;
+	}
+
+	.info-dot::before {
+		content: '';
+		position: absolute;
+		width: 12rpx;
+		height: 12rpx;
+		border-radius: 50%;
+		top: calc(50% - 6rpx);
+		left: 0;
+		background: #4794FF;
 	}
 
-	.page4-form {
+	.flow-list {
+		margin: 24rpx !important;
 		padding: 30rpx;
 		border-radius: 10rpx;
 		background-color: #fff;
 	}
 
+	.flow-time {
+		font-size: 28rpx;
+		color: #888888;
+	}
+
+	.flow-des {
+
+		&-bg {
+			background: rgba(115, 190, 255, 0.08);
+			border-radius: 8rpx 8rpx 8rpx 8rpx;
+			padding: 24rpx 40rpx 30rpx 40rpx;
+			margin-top: 10rpx;
+		}
+
+		&-top {
+			font-size: 32rpx;
+			color: #222222;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+
+			&-tips {
+				font-size: 28rpx;
+				color: #207DFF;
+			}
+
+			&-tips1 {
+				color: #1FBC99;
+			}
+
+			&-tips0 {
+				color: #FA7E00;
+			}
+
+			&-tips2 {
+				color: #fa3534;
+			}
+		}
+
+		&-des {
+			margin-top: 25rpx;
+			font-size: 28rpx;
+			color: #888888;
+		}
+	}
+
+	.flow-des-img {
+		display: flex;
+		gap: 10rpx;
+		flex-wrap: wrap;
+		margin: 10rpx 0;
+	}
+
 	.btn-box {
 		padding: 20rpx 36rpx;
 		background-color: #fff;
 		position: fixed;
 		bottom: calc(50px + var(--status-bar-height));
 		/* bottom: 50px; */
-		left: 0;
 		width: 690rpx;
+
+		.btn-place {
+			width: 50rpx;
+		}
 	}
 </style>

+ 41 - 4
pages/subpack/pages/application/list.vue

@@ -32,7 +32,9 @@
 		useStore
 	} from 'vuex';
 	import {
-		getCareList
+		getCareList,
+		getAppClockList,
+		getAssignList
 	} from '@/common/config/application-api.js'
 	import {
 		onLoad,
@@ -206,11 +208,46 @@
 				...query
 			}
 		}
-
+		if(roles.includes('company')){
+			getListIsCompany(params);
+		}else if(roles.includes('nurse')) {
+			getListIsNurse(params);
+		}else {
+			getList(params);
+		}
+		
+	}
+	
+	function getList(params) {
 		getCareList({
-			params: params
+			params
 		}).then(data => {
-			// console.log('getCareList=>', data);
+			paging.value.complete(data);
+		})
+	}
+	
+	// -护理公司护理列表查询
+	function getListIsCompany(query) {
+		let params = {
+			...query,
+			pageNumAssign: query.pageNum??1,
+			pageSizeAssign: query.pageSize??10
+		}
+		getAssignList({
+			params
+		}).then(data=>{
+			paging.value.complete(data);
+		})
+	}
+	
+	// -护理人员护理列表查询
+	function getListIsNurse(query) {
+		let params = {
+			...query
+		}
+		getAppClockList({
+			params
+		}).then(data=>{
 			paging.value.complete(data);
 		})
 	}

+ 268 - 0
pages/subpack/pages/nurse/clockIn.vue

@@ -0,0 +1,268 @@
+<template>
+  <view class="page4-warp">
+    <u-navbar class="u-navbar-box" title="护理打卡" placeholder bgColor="transparent" autoBack/>
+    <view class="page4-form">
+      <up-form labelPosition="top" :model="formData" :rules="formRule" ref="formRef">
+        <up-form-item label="护理时间" labelWidth="auto" labelPosition="left" required prop="nursingTime">
+          <up-input v-model="formData.nursingTime" disabled disabledColor="#ffffff" border="bottom"
+                    placeholder="请选择打卡时间" @tap="showTime = true;"/>
+        </up-form-item>
+        <up-form-item :label="`护理打卡(最少上传${imgNum}张图片)`" labelWidth="auto" prop="img" required>
+          <view class="flex-row justify-between align-center" style="width: 100%;">
+            <up-upload :fileList="fileList" multiple :sizeType="['compressed']" :capture="['camera']"
+                       @afterRead="afterRead" @delete="deletePic"/>
+          </view>
+        </up-form-item>
+        <up-form-item label="备注" labelWidth="auto">
+          <up-textarea v-model="formData.remark" placeholder="请输入您的打卡备注" count/>
+        </up-form-item>
+      </up-form>
+    </view>
+
+    <u-datetime-picker ref="datetimePicker" :show="showTime" v-model="timeValue" mode="datetime" closeOnClickOverlay
+                       @cancel="showTime = false" @close="showTime = false" @confirm="timeConfirm"
+                       :formatter="formatter"/>
+    <view class="btn-box">
+      <view class="flex-row ">
+        <up-button class="up-button" type="primary" @tap="checkTap">确定打卡</up-button>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import {
+  ref,
+  reactive,
+  computed,
+  onMounted
+} from 'vue';
+import {
+  useStore
+} from 'vuex';
+import {
+  onLoad,
+  onUnload,
+  onReady
+} from "@dcloudio/uni-app"
+import {
+  getImgNumber,
+  addCareClocks,
+  uploadImgUrl
+} from '@/common/config/application-api.js'
+
+
+const store = useStore();
+const props = defineProps({
+  item: {
+    type: Object,
+    default() {
+      return {}
+    }
+  }
+})
+
+const showTime = ref(false);
+const timeValue = ref(new Date().getTime());
+const formRef = ref(null);
+const fileList = ref([]);
+const formData = reactive({
+  img: [],
+  remark: '', //意见
+  nursingTime: '', //护理时间
+})
+const formRule = reactive({
+  nursingTime: [{
+    required: true,
+    message: '请选择护理时间',
+    trigger: ['blur', 'change']
+  }],
+  img: [{
+    validator: (rule, value, callback) => {
+      return value.length >= imgNum.value;
+    },
+    message: '请上传指定数量的图片',
+    trigger: ['change', 'blur'],
+  }]
+})
+
+//点击打卡
+function checkTap() {
+  // console.log('1=>', fileList.value);
+  formData.img = [];
+  fileList.value.map(file => {
+    formData.img.push(file.url);
+  });
+  // console.log('2=>', formData);
+  formRef.value.validate().then(res => {
+    if (res) {
+      formData.imgPaths = formData.img.join(',');
+      formData.imgNum = formData.img.length;
+      delete formData.img;
+      addClocks();
+      // uni.$u.toast('校验通过')
+    }
+  })
+}
+
+//点击打卡 --新增打卡记录
+function addClocks() {
+  let reqClockParams = {
+    applyId: props.item.applyId,
+    nursingRecordId: props.item.applyId,
+    ...formData
+  }
+  // console.log('reqClockParams=>', reqClockParams);
+  addCareClocks(reqClockParams)
+      .then(res => uni.$u.toast('打卡成功!'))
+      .catch(error => uni.$u.toast('打卡失败!'));
+}
+
+const datetimePicker = ref();
+onReady(() => {
+  datetimePicker.value.setFormatter(formatter);
+})
+
+function formatter(type, value) {
+  if (type === 'year') {
+    return `${value}年`
+  }
+  if (type === 'month') {
+    return `${value}月`
+  }
+  if (type === 'day') {
+    return `${value}日`
+  }
+  if (type === 'hour') {
+    return `${value}时`
+  }
+  if (type === 'minute') {
+    return `${value}分`
+  }
+  return value
+}
+
+function timeConfirm(e) {
+  // console.log('timeConfirm=>', e);
+  timeValue.value = e.value;
+  formData.nursingTime = uni.$u.timeFormat(e.value, 'yyyy-mm-dd hh:MM:ss');
+  showTime.value = false;
+}
+
+//删除图片
+function deletePic(event) {
+  fileList.value.splice(event.index, 1);
+}
+
+//新增图片
+async function afterRead(event) {
+  // 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
+  let lists = [].concat(event.file);
+  let fileListLen = fileList.value.length;
+  lists.map((item) => {
+    fileList.value.push({
+      ...item,
+      status: "uploading",
+      message: "上传中",
+    });
+  });
+  for (let i = 0; i < lists.length; i++) {
+    const result = await uploadFilePromise(lists[i].url);
+    console.log('result=>', result);
+    let item = fileList.value[fileListLen];
+    fileList.value.splice(
+        fileListLen,
+        1,
+        Object.assign(item, {
+          status: "success",
+          message: "",
+          url: result,
+        })
+    );
+    fileListLen++;
+  }
+  // console.log('fileList=>', fileList);
+}
+
+/**
+ * TODO 上传图片有问题,上传的时间是选择 还是当前时间
+ * 如果今天上传的护理记录  是否还可以继续上传 一天上传几次护理打卡记录
+ * 思路 2/23  page4 里面显示打卡记录  然后打卡记录里面可能是死亡/打卡/结束几个按钮
+ * 从page4 里面进入打卡页面和死亡表单页面
+ *
+ *
+ */
+
+//上传图片
+function uploadFilePromise(url) {
+  return new Promise((resolve, reject) => {
+    //前缀
+    let prefix =  uni.$u.http.config.baseURL;
+    let a = uni.uploadFile({
+      url: `${prefix}${uploadImgUrl}`,
+      filePath: url,
+      name: "file",
+      formData: {
+        applyId: props.item.applyId,
+      },
+      success: (res) => {
+        let data = {
+          imgUrl: ''
+        };
+        try {
+          let resData = res.data;
+          data = JSON.parse(resData);
+        } catch (error) {
+          console.error(error);
+        } finally {
+          resolve(data.imgUrl);
+        }
+      },
+    });
+  });
+}
+
+//获取打卡图片数量
+const imgNum = ref(0);
+
+function getNumber() {
+  getImgNumber({
+    params: {
+      key: 'need_img_num'
+    }
+  }).then(res => {
+    imgNum.value = res.number;
+  })
+}
+
+onMounted(() => {
+  getNumber();
+})
+</script>
+
+<style lang="scss" scoped>
+:deep(.u-navbar__content__title) {
+  font-weight: bold;
+  font-size: 36rpx;
+  color: #222222;
+}
+
+.u-navbar-box {
+  background: radial-gradient(circle at left, #FFE5E4 0%, #EEF2F5 40%, #DBEEFB 100%);
+}
+
+.page4-form {
+  padding: 30rpx;
+  border-radius: 10rpx;
+  background-color: #fff;
+}
+
+.btn-box {
+  padding: 20rpx 36rpx;
+  background-color: #fff;
+  position: fixed;
+  bottom: 10rpx;
+  left: 0;
+  width: 690rpx;
+}
+</style>

+ 13 - 0
pages/subpack/pages/nurse/death.vue

@@ -0,0 +1,13 @@
+<template>
+	<view>
+		
+	</view>
+</template>
+
+<script setup>
+	
+</script>
+
+<style>
+	       
+</style>

BIN
pages/subpack/static/images/error-img.png


+ 2 - 2
utils/request/index.js

@@ -11,9 +11,9 @@ import {
 const initRequest = (vm) => {
 	http.setConfig((defaultConfig) => {
 		// defaultConfig.baseURL = 'http://133.46.152.185' /* 根域名 */
-		defaultConfig.baseURL = 'http://tkhtest.natapp1.cc' /* 根域名 */
 		// defaultConfig.baseURL = 'http://tkhtest.natapp1.cc' /* 根域名 */
-		// defaultConfig.baseURL = 'http://127.0.0.1' /* 根域名 */
+		// defaultConfig.baseURL = 'http://tkhtest.natapp1.cc' /* 根域名 */
+		defaultConfig.baseURL = 'http://127.0.0.1' /* 根域名 */
 		defaultConfig = {
 			...defaultConfig,
 			custom: {