فهرست منبع

新增客户合同

tanxue 53 دقیقه پیش
والد
کامیت
523837f7dd

+ 0 - 0
api/hetong.js → api/jzHetong.js


+ 48 - 0
api/khHetong.js

@@ -0,0 +1,48 @@
+import request from '@/utils/request'
+export function getHetongLast(data = {}) {
+  return request({
+    url: '/app/guanliyuan/hetong/last/info',
+    headers: {
+      isToken: true
+    },
+    method: 'post',
+    data,
+    timeout: 20000
+  })
+}
+export function getHetongList(data = {}) {
+  return request({
+    url: '/app/guanliyuan/hetong/list',
+    headers: {
+      isToken: true
+    },
+    method: 'post',
+    data,
+    timeout: 20000
+  })
+}
+export function getHetongQianming(data = {}) {
+  return request({
+    url: '/app/guanliyuan/hetong/qianming',
+    headers: {
+      isToken: true
+    },
+    method: 'post',
+    data,
+    timeout: 20000
+  })
+}
+
+export function getHetongInfo(data = {}) {
+  return request({
+    url: '/app/guanliyuan/hetong/info',
+    headers: {
+      isToken: true
+    },
+    method: 'post',
+    data,
+    timeout: 20000
+  })
+}
+
+

+ 156 - 0
pages/client/hetong/HetongInfo.vue

@@ -0,0 +1,156 @@
+<template>
+	<view class="phone-hetong-page">
+		<view class="phone-navBar-box">
+			<view @click="goUpPage" class="nav-bar-icon"></view>
+			<text class="nav-bar-title">合同</text>
+			<view class="lsht-icon" @click="handleGoLishi"></view>
+		</view>
+		<template v-if="tId">
+			<view class="pdf-box">
+				<img v-for="item in imgList" mode="aspectFit" :src="`data:image/png;base64,${item}`"
+					@click="previewBase64Image(`data:image/png;base64,${item}`)" class="pdf-img" />
+			</view>
+			<!-- 加载提示 -->
+			<view class="pdf-tip-box" v-if="isLoading">
+				<view class="tip-img-box">
+					 <view class="tip-text">加载中...</view>
+				</view>
+			</view>
+		</template>
+
+		<view class="hetong-tip-box" v-if="tId && info.status == 0">
+			请务必仔细阅读上述内容,确认已完全理解所有条款后,点击【我已阅读】按钮完成签字确认。
+		</view>
+		<button @click="handleQianming" v-if="tId && info.status == 0" class="phone-green-btn ht-btn"
+			type="default">我已阅读</button>
+
+		<uni-popup ref="popupRef" type="bottom" background-color="#fff" :is-mask-click="false" :mask-click="false">
+			<view class="ht-qm-popup">
+				<view class="icon-title-navBar-box">
+					<view @click="goback2" class="nav-bar-icon"></view>
+					<text class="nav-bar-title">签名</text>
+				</view>
+				<writeSign @getBase64="getBase64"></writeSign>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref
+	} from "vue";
+	import * as httpApi from "@/api/jzHetong.js"
+	import {
+		onLoad
+	} from "@dcloudio/uni-app"
+	import writeSign from "@/components/writeSign/index.vue"
+	import {
+		throttleAdvanced
+	} from "@/utils/common.js"
+	import {
+		base64ToPath
+	} from "image-tools";
+
+	const tId = ref(null)
+
+	const info = ref({})
+	const show = ref(false)
+	const popupRef = ref(null)
+	const imgList = ref([])
+	const isLoading = ref(true)
+	const timer1 = ref(null)
+
+	onLoad((options) => {
+		tId.value = options.id;
+		init();
+	})
+
+	function handleQianming() {
+		popupRef.value.open()
+	}
+
+	function init() {
+		httpApi.getHetongInfo({
+			id: tId.value
+		}).then(res => {
+			info.value = res.data;
+			imgList.value = res.data.base64List;
+		}).finally(() => {
+			isLoading.value = false;
+		})
+	}
+
+	async function previewBase64Image(base64Data) {
+		try {
+			// 关键步骤:将 Base64 字符串转换为本地临时路径
+			// 此处以使用 image-tools 的 base64ToPath 为例
+			const localPath = await base64ToPath(base64Data);
+			// 调用 UniApp 的图片预览 API
+			uni.previewImage({
+				urls: [localPath], // 注意:urls 参数需要是数组,即使只预览一张图
+				current: 0, // 当前显示图片在 urls 数组中的索引
+			});
+		} catch (error) {
+			// 如果出现错误(如转换失败),隐藏加载提示并告知用户
+			console.error('预览失败:', error);
+			uni.showToast({
+				title: '预览失败',
+				icon: 'none'
+			});
+		}
+	}
+
+	function goUpPage() {
+		uni.navigateBack()
+		clearTimeout(timer1.value);
+		timer1.value = null;
+	}
+
+	const handleQM = throttleAdvanced((img) => {
+		uni.showToast({
+			title: "签名提交中...",
+			mask: true,
+		})
+
+		httpApi.getHetongQianming({
+			id: tId.value,
+			yifangBase64: img.replace(/^data:image\/\w+;base64,/, '')
+		}).then(res => {
+			if (res.data) {
+				uni.showToast({
+					title: "签名成功",
+					duration: 2000,
+					mask: true,
+					success() {
+						timer1.value = setTimeout(() => goUpPage(), 2000)
+					}
+				})
+			}
+		})
+	})
+
+	function getBase64(img) {
+		if (!img) {
+			uni.showToast({
+				title: '签名异常'
+			})
+			return;
+		}
+		handleQM(img)
+
+	}
+	function handleGoLishi() {
+		uni.redirectTo({
+			url: '/pages/admin/Hetong/HetongList'
+		})
+	}
+
+	function goback2() {
+		popupRef.value.close()
+	}
+</script>
+
+<style scoped>
+
+</style>

+ 163 - 0
pages/client/hetong/HetongList.vue

@@ -0,0 +1,163 @@
+<template>
+	<view class="phone-list-page ht-list-page">
+		<view class="icon-title-navBar-box">
+			<view @click="goUpPage" class="nav-bar-icon"></view>
+			<text class="nav-bar-title">历史合同</text>
+		</view>
+	<!-- 课程列表 -->
+	<scroll-view scroll-y="true" refresher-enabled="true" :refresher-triggered="data.loading"
+		:refresher-threshold="50" refresher-background="transparent" @refresherrefresh="onRefresh"  @scrolltolower="onScrolltolower"
+		class="admin-phone-tabbar-view">
+		<uni-list class="admin-list-box ht-list-box">
+			<uni-list-item v-for="item in data.list" class="ht-list-item-box">
+				<template v-slot:body>
+					<view class="ht-card-row">
+						<view class="ht-status-btn-row">
+							<view class="ht-status">合同状态:<view :class="'status-' + item.status">{{formatStatus(item.status)}}</view></view>
+							<view class="ht-biew-btn" @click="checkKecheng(item)">查看<icon class="ht-jt"></icon></view>
+						</view>
+						<view class="ht-time"><icon class="phone-time-icon" />合同开始时间:{{formatTime(item.startDate)}} </view>
+						<view class="ht-time"><icon class="phone-time-icon" />合同结束时间:{{formatTime(item.endDate)}} </view>
+					</view>
+				</template>
+			</uni-list-item>
+			<uni-load-more :status="data.state" @click="getMore(0)" :contentText="data.contentText"></uni-load-more>
+		</uni-list>
+	</scroll-view>
+	<!-- 页面底端 -->
+	<customTabbarClientVue></customTabbarClientVue>
+	</view>
+</template>
+
+<script setup>
+import {ref,reactive} from "vue";
+import {onLoad,onShow} from "@dcloudio/uni-app";
+import {getHetongList} from '@/api/jzHetong.js'
+import customTabbarClientVue from "@/components/custom-tabbar/custom-tabbar-admin.vue";
+const data = reactive({
+		list: [], // 考试列表
+		loading: false,
+		page: 0,
+		size: 10,
+		state: 'more',
+		contentText: {
+			contentdown: '查看更多',
+			contentrefresh: '加载中',
+			contentnomore: '没有更多'
+		},
+})	
+	
+onLoad((options) => {
+		data.from = options.from;
+		
+	})
+
+onShow(() => {
+  refreshData()
+})
+
+function onRefresh() {
+	data.page = 0;
+	data.list = [];
+	data.loading = true;
+	refreshData();
+}
+
+function refreshData() {
+	const opt = {
+		page: 1,
+		size: 10, // 固定查询10条
+	}
+	data.list = [];
+	// 数学
+	data.state = 'loading';
+	data.page++;
+	opt.page = data.page;
+	
+	    console.log('列表',opt)
+	
+	getHetongList(opt).then(res => {
+
+
+
+		data.list = data.list.concat(res.data.data);
+		data.loading = false;
+		if (res.data.total > data.list.length) {
+			data.state = 'more';
+			data.loading = false;
+		} else {
+			data.state = 'no-more';
+			data.loading = false;
+		}
+	}).catch(err => {
+		data.state = 'more';
+		data.loading = false;
+	})
+}
+
+function getMore() {
+	const opt = {
+		page: 1,
+		size: 10, // 固定查询10条
+	}
+	if (data.state == 'no-more') return;
+	data.state = 'loading';
+	data.page++;
+	opt.page = data.page;
+	getHetongList(opt).then(res => {
+    console.log('列表2',res.data)
+
+    data.list = data.list.concat(res.data.data);
+		data.loading = false;
+		if (res.data.total > data.list.length) {
+			data.state = 'more';
+			data.loading = false;
+		} else {
+			data.state = 'no-more';
+			data.loading = false;
+		}
+	}).catch(err => {
+		data.state = 'more';
+		data.loading = false;
+	})
+}
+
+function onScrolltolower() {
+	getMore()
+}
+
+function handleSearch() {
+	data.page = 0;
+	refreshData();
+}
+
+// 在现有代码底部添加此方法
+function formatStatus(status) {
+  const statusMap = {
+    0: '待签字',
+    1: '待审核',
+    2: '生效',
+	3: '失效',
+  };
+  return statusMap[status] || '未知状态'; // 处理未知状态
+}
+
+function formatTime(data){
+		return data.split(' ')[0];
+}
+
+function checkKecheng(item) {
+	uni.navigateTo({
+		url: `/pages/admin/Hetong/HetongInfo?id=${item.id}`
+	})
+}
+
+function goUpPage() {
+	uni.redirectTo({
+		url: '/pages/admin/ShouYe/shouye'
+	})	
+}
+</script>
+
+<style>
+</style>

+ 153 - 0
pages/client/hetong/hetong.vue

@@ -0,0 +1,153 @@
+<template>
+	<view class="phone-hetong-page">
+		<view class="phone-navBar-box">
+			<view @click="goUpPage" class="nav-bar-icon"></view>
+			<text class="nav-bar-title">合同</text>
+		</view>
+		<template v-if="tId">
+			<view class="pdf-box"> 
+				 <img v-for="item in imgList" mode="aspectFit" :src="`data:image/png;base64,${item}`" 
+				 @click="previewBase64Image(`data:image/png;base64,${item}`)" class="pdf-img"/>
+			</view>
+			<!-- 加载提示 -->
+			<view class="pdf-tip-box" v-if="isLoading">
+				<view class="tip-img-box">
+					 <view class="tip-text">加载中...</view>
+				</view>
+			</view>
+		</template>
+		<view class="hetong-tip-box" v-if="info.status == 0">
+				  请务必仔细阅读上述内容,确认已完全理解所有条款后,点击【我已阅读】按钮完成签字确认。
+		</view>
+		<button v-if="info.status == 0" type="default" class="phone-green-btn ht-btn"
+			@click="handleQianming">我已阅读</button>
+
+		<uni-popup ref="popupRef" type="bottom" background-color="#fff" :is-mask-click="false" :mask-click="false">
+			<view class="ht-qm-popup">
+				<view class="icon-title-navBar-box">
+					<view @click="goback2" class="nav-bar-icon"></view>
+					<text class="nav-bar-title">签名</text>
+				</view>
+				<writeSign @getBase64="getBase64"></writeSign>
+			</view>
+		</uni-popup>
+		
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref
+	} from "vue";
+	import * as httpApi from "@/api/jzHetong.js"
+	import {
+		onLoad
+	} from "@dcloudio/uni-app"
+	import writeSign from "@/components/writeSign/index.vue"
+  import {throttleAdvanced} from "@/utils/common.js"
+  import { base64ToPath } from 'image-tools';
+
+	const tId = ref(null)
+	const info = ref({})
+	const popupRef = ref(null)
+	const imgList = ref([])
+	const isLoading = ref(true)
+  const timer1 = ref(null)
+
+	function goUpPage() {
+		uni.navigateBack()
+    clearTimeout(timer1.value);
+    timer1.value = null;
+	}
+	onLoad(({id}) => {
+    tId.value = id;
+		init(id)
+	})
+
+	function init(id) {
+		if (!id) {
+			uni.showToast({
+				title: '数据异常,请确认路径是否完整'
+			})
+			return;
+		}
+
+		httpApi.getHetongInfo({id}).then(res => {
+			info.value = res.data;
+			imgList.value = res.data.base64List;
+		}).finally(() => {
+			isLoading.value = false;
+		})
+	}
+
+  async function previewBase64Image(base64Data) {
+      try {
+        // 关键步骤:将 Base64 字符串转换为本地临时路径
+        // 此处以使用 image-tools 的 base64ToPath 为例
+        const localPath = await base64ToPath(base64Data);
+        // 调用 UniApp 的图片预览 API
+        uni.previewImage({
+          urls: [localPath], // 注意:urls 参数需要是数组,即使只预览一张图
+          current: 0, // 当前显示图片在 urls 数组中的索引
+        });
+      } catch (error) {
+        // 如果出现错误(如转换失败),隐藏加载提示并告知用户
+        console.error('预览失败:', error);
+        uni.showToast({
+          title: '预览失败',
+          icon: 'none'
+        });
+      }
+  }
+
+	function handleGoLishi() {
+		uni.redirectTo({
+			url: '/pages/admin/Hetong/HetongList'
+		})
+	}
+
+	function handleQianming() {
+		popupRef.value.open()
+	}
+
+  const  handleQM = throttleAdvanced((img) => {
+    uni.showToast({
+      title: "签名提交中...",
+      mask: true,
+    })
+
+    httpApi.getHetongQianming({
+      id: tId.value,
+      yifangBase64: img.replace(/^data:image\/\w+;base64,/, ''), // 当前接口,只有唯一yifangBase64 + id
+    }).then(res => {
+      if (res.data) {
+        uni.showToast({
+          title: "签名成功",
+          duration: 2000,
+          mask: true,
+          success() {
+            timer1.value = setTimeout(() => uni.navigateBack(),2000)
+          }
+        })
+      }
+    })
+  })
+
+	function getBase64(img) {
+		if (!img) {
+			uni.showToast({
+				title: '签名异常'
+			})
+			return;
+		}
+    handleQM(img)
+	}
+
+	function goback2() {
+		popupRef.value.close()
+	}
+</script>
+
+<style>
+
+</style>

+ 1 - 1
pages/kehu/hetong/HetongInfo.vue

@@ -40,7 +40,7 @@
 	import {
 		ref
 	} from "vue";
-	import * as httpApi from "@/api/hetong.js"
+	import * as httpApi from "@/api/khHetong.js"
 	import {
 		onLoad
 	} from "@dcloudio/uni-app"

+ 1 - 1
pages/kehu/hetong/HetongList.vue

@@ -32,7 +32,7 @@
 <script setup>
 import {ref,reactive} from "vue";
 import {onLoad,onShow} from "@dcloudio/uni-app";
-import {getHetongList} from '@/api/hetong.js'
+import {getHetongList} from '@/api/khHetong.js'
 import customTabbarClientVue from "@/components/custom-tabbar/custom-tabbar-admin.vue";
 const data = reactive({
 		list: [], // 考试列表

+ 1 - 1
pages/kehu/hetong/hetong.vue

@@ -39,7 +39,7 @@
 	import {
 		ref
 	} from "vue";
-	import * as httpApi from "@/api/hetong.js"
+	import * as httpApi from "@/api/khHetong.js"
 	import {
 		onLoad
 	} from "@dcloudio/uni-app"