From 197e3949af92e687e9e06bd2daf539b6b665d06d Mon Sep 17 00:00:00 2001
From: wujingjing <gersonwu@qq.com>
Date: 星期五, 21 三月 2025 18:17:52 +0800
Subject: [PATCH] 微信绑定

---
 src/layout/navBars/breadcrumb/user.vue                              |    4 
 src/api/login/UserMenuData.ts                                       |   17 +
 src/hooks/useLogin.ts                                               |    3 
 src/views/project/yw/systemManage/personalCenter/PersonalCenter.vue |  425 +++++++++++++++++++++++++++++++++++++++++++++++
 src/utils/global.ts                                                 |   31 ++
 customer_list/yw/static/config/route.js                             |    7 
 6 files changed, 477 insertions(+), 10 deletions(-)

diff --git a/customer_list/yw/static/config/route.js b/customer_list/yw/static/config/route.js
index 94d0bee..a4d411d 100644
--- a/customer_list/yw/static/config/route.js
+++ b/customer_list/yw/static/config/route.js
@@ -106,6 +106,13 @@
 		component: '/project/yw/systemManage/replaceWordMgr/ReplaceWordMgr.vue',
 	},
 	{
+		name: 'PersonalCenter',
+		isKeepAlive: true,
+		isAffix: false,
+		path: '/personalCenter',
+		component: '/project/yw/systemManage/personalCenter/PersonalCenter.vue',
+	},
+	{
 		name: 'AmisEditor',
 		isKeepAlive: true,
 		isAffix: false,
diff --git a/src/api/login/UserMenuData.ts b/src/api/login/UserMenuData.ts
index 8bf6283..cb9d4ad 100644
--- a/src/api/login/UserMenuData.ts
+++ b/src/api/login/UserMenuData.ts
@@ -456,6 +456,23 @@
 				SortCode: 2,
 				Description: '',
 			},
+
+			{
+				Children: [],
+				ID: '1135',
+				ParentID: '3',
+				Type: 2,
+				Name: '涓汉涓績',
+				Path: '/personalCenter',
+				Permission: '',
+				Icon: 'ywifont ywicon-wode',
+				IsIframe: false,
+				OutLink: '',
+				IsHide: true,
+				Weight: 0,
+				SortCode: 2,
+				Description: '',
+			},
 			{
 				Children: [],
 				ID: '333-2',
diff --git a/src/hooks/useLogin.ts b/src/hooks/useLogin.ts
index d57cc72..6c8d6b2 100644
--- a/src/hooks/useLogin.ts
+++ b/src/hooks/useLogin.ts
@@ -69,8 +69,7 @@
 		const currentTime = formatAxis(new Date());
 		Local.set(accessSessionKey, res.hswatersession);
 		await useUserInfo().setUserInfos({
-			userName: res.name,
-			phoneNumber: res.phone,
+			...(res ?? {}),
 			photo: profileMan,
 		}); //缂撳瓨鐢ㄦ埛淇℃伅
 		// state.loading.signIn = true;
diff --git a/src/layout/navBars/breadcrumb/user.vue b/src/layout/navBars/breadcrumb/user.vue
index 9e8a684..59486cc 100644
--- a/src/layout/navBars/breadcrumb/user.vue
+++ b/src/layout/navBars/breadcrumb/user.vue
@@ -63,7 +63,7 @@
 		<el-dropdown :show-timeout="70" :hide-timeout="50" @command="onHandleCommandClick">
 			<span class="layout-navbars-breadcrumb-user-link">
 				<img :src="userInfos.photo" class="layout-navbars-breadcrumb-user-link-photo mr5" />
-				{{ userInfos.userName === '' ? 'common' : userInfos.userName }}
+				{{ userInfos.name === '' ? 'common' : userInfos.name }}
 				<el-icon class="el-icon--right">
 					<ele-ArrowDown />
 				</el-icon>
@@ -75,7 +75,7 @@
 
 					<el-dropdown-item command="/404">{{ $t('message.user.dropdown3') }}</el-dropdown-item>
 					<el-dropdown-item command="/401">{{ $t('message.user.dropdown4') }}</el-dropdown-item> -->
-					<!-- <el-dropdown-item command="/auth/personalCenter">{{ $t('message.user.dropdown2') }}</el-dropdown-item> -->
+					<el-dropdown-item command="/personalCenter">{{ $t('message.user.dropdown2') }}</el-dropdown-item>
 					<el-dropdown-item divided command="logOut">{{ $t('message.user.dropdown5') }}</el-dropdown-item>
 				</el-dropdown-menu>
 			</template>
diff --git a/src/utils/global.ts b/src/utils/global.ts
index 25df7e1..2c15dff 100644
--- a/src/utils/global.ts
+++ b/src/utils/global.ts
@@ -56,7 +56,7 @@
 			value: res?.json_msg ?? '鐧诲綍澶辫触锛岃妫�鏌ユ槸鍚﹀凡缁戝畾寰俊',
 		});
 
-		window.location.href = SERVE_URL;
+		// window.location.href = SERVE_URL;
 	}
 };
 
@@ -65,23 +65,42 @@
 
 	const res = await userBindingWechat({
 		weixin_code: wxcode,
-		user_name: userInfo.userName,
+		user_name: userInfo.name,
 	});
+
+	const reloadPage = () => {
+		const url = window.location.href;
+		const [baseUrl, hash] = url.split('#/');
+		const [path, search] = hash.split('?');
+
+		if (search) {
+			const searchParams = new URLSearchParams(search);
+			searchParams.delete('isWxLogin');
+			searchParams.delete('wxcode');
+			searchParams.delete('wxstate');
+
+			const newSearch = searchParams.toString();
+			const newUrl = `${baseUrl}#/${path}${newSearch ? '?' + newSearch : ''}`;
+			window.history.replaceState({}, '', newUrl);
+			window.location.reload();
+		}
+	};
 	if (res?.json_ok) {
 		ElMessage.success('缁戝畾鎴愬姛');
 		const userInfo = Local.get(userInfoKey);
 		Local.set(userInfoKey, {
 			...userInfo,
-			isBindWechat: true,
-			wechatNickname: res.json_url,
+			/** @description 闅忎究璁剧疆涓�涓�硷紝琛ㄧず宸茬粡缁戝畾浜� */
+			weixin_openid: 'sdfdf',
+			weixin_nickname: res.json_url,
 		});
 		setTimeout(() => {
-			window.location.href = SERVE_URL;
+			reloadPage();
 		}, 700);
 	} else {
 		ElMessage.error(res?.json_msg ?? '缁戝畾澶辫触');
 		setTimeout(() => {
-			window.location.href = SERVE_URL;
+			reloadPage();
 		}, 2000);
 	}
 };
diff --git a/src/views/project/yw/systemManage/personalCenter/PersonalCenter.vue b/src/views/project/yw/systemManage/personalCenter/PersonalCenter.vue
new file mode 100644
index 0000000..57c0b4c
--- /dev/null
+++ b/src/views/project/yw/systemManage/personalCenter/PersonalCenter.vue
@@ -0,0 +1,425 @@
+<template>
+	<div class="sys-userCenter-container h100">
+		<el-row :gutter="8" style="width: 100%" class="h100">
+			<el-col :span="8" :xs="24" class="h100">
+				<el-card shadow="hover" class="h100">
+					<div class="account-center-avatarHolder">
+						<el-avatar
+							:size="100"
+							:src="userInfos.photo"
+							@click="openCropperDialog"
+							v-loading="state.avatarLoading"
+							element-loading-spinner="el-icon-Upload"
+							element-loading-background="rgba(0, 0, 0, 0.2)"
+							@mouseenter="mouseEnterAvatar"
+							@mouseleave="mouseLeaveAvatar"
+						/>
+						<div class="username">{{ userInfos.realName }}</div>
+					</div>
+					<div class="account-center-org" style="display: flex; flex-direction: column; align-items: center">
+						<div>
+							<p class="user-simple-info">
+								<!-- 鐢ㄦ埛鍚� -->
+								<el-icon size="17" class="mr10"><ele-User /></el-icon> <span>{{ userInfos?.name ?? '---' }}</span>
+							</p>
+							<!-- 鍏徃鍚� -->
+							<!-- <p class="user-simple-info">
+								<el-icon size="17"><ele-Briefcase /></el-icon> <span>{{ userInfos.SoftWare?.Project?.Corpration?.Name ?? '---' }}</span>
+							</p> -->
+							<p class="user-simple-info" v-if="userInfos?.weixin_nikename">
+								<!-- 璐︽埛绫诲瀷鍚� -->
+								<span class="ywifont ywicon-weixin mr10"></span>
+								<span>{{ userInfos?.weixin_nikename ?? '---' }}</span>
+							</p>
+						</div>
+					</div>
+				</el-card>
+			</el-col>
+
+			<el-col :span="16" :xs="24" class="h100" v-loading="state.loading">
+				<el-card shadow="hover" class="h100">
+					<el-tabs>
+						<el-tab-pane label="鍩虹淇℃伅">
+							<el-form :model="state.ruleFormBase" ref="ruleFormBaseRef" label-width="80px">
+								<el-row :gutter="35">
+									<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+										<el-form-item label="鐢ㄦ埛ID">
+											<el-input :model-value="userInfos?.name" placeholder="鐢ㄦ埛ID" />
+										</el-form-item>
+									</el-col>
+									<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+										<el-form-item label="濮撳悕">
+											<el-input :model-value="userInfos?.real_name" placeholder="濮撳悕" />
+										</el-form-item>
+									</el-col>
+									<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+										<el-form-item label="鎬у埆">
+											<el-input :model-value="userInfos?.sex" placeholder="鎬у埆" />
+										</el-form-item>
+									</el-col>
+									<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+										<el-form-item label="閮ㄩ棬">
+											<el-input :model-value="userInfos?.part" placeholder="閮ㄩ棬" />
+										</el-form-item>
+									</el-col>
+									<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+										<el-form-item label="鐢佃瘽">
+											<el-input :model-value="userInfos?.phone" placeholder="鐢佃瘽" />
+										</el-form-item>
+									</el-col>
+									<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+										<el-form-item label="閭">
+											<el-input :model-value="userInfos?.email" placeholder="閭" />
+										</el-form-item>
+									</el-col>
+									<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+										<el-form-item label="寰俊鏄电О">
+											<el-input :model-value="userInfos?.weixin_nikename" placeholder="寰俊鏄电О" />
+										</el-form-item>
+									</el-col>
+
+									
+									<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+										<el-form-item label="寰俊缁戝畾" prop="wechat">
+											<div id="wechat-bind">
+												<div v-if="bindingCodeShow" class="flex flex-col items-center justify-center">
+													<iframe
+														ref="wechatQrRef"
+														sandbox="allow-top-navigation allow-scripts"
+														style="width: 200px; height: 170px; overflow: hidden"
+														frameborder="0"
+													></iframe>
+													<span>浣跨敤寰俊鎵竴鎵粦瀹�</span>
+												</div>
+												<template v-else>
+													<div v-if="userInformationInfo.weixin_openid" class="flex items-center">
+														<span>宸茬粦瀹�</span>
+														<el-button link type="primary" @click="openWechatLogin">閲嶆柊缁戝畾</el-button>
+													</div>
+													<div v-else class="flex items-center">
+														<span>鏈粦瀹�</span>
+														<el-button link type="primary" @click="openWechatLogin">鐐瑰嚮缁戝畾</el-button>
+													</div>
+												</template>
+											</div>
+										</el-form-item>
+									</el-col>
+								</el-row>
+							</el-form>
+						</el-tab-pane>
+
+						<el-tab-pane label="淇敼瀵嗙爜">
+							<el-form ref="ruleFormPasswordRef" :model="state.ruleFormPassword" label-width="80px">
+								<el-form-item
+									label="鏂板瘑鐮�"
+									prop="passwordNew"
+									:rules="[{ required: true, message: '鏂板瘑鐮佷笉鑳戒负绌�', trigger: 'blur' }]"
+								>
+									<el-input
+										v-model="state.ruleFormPassword.passwordNew"
+										:type="state.showPasswdNew ? 'text' : 'password'"
+										autocomplete="off"
+									>
+										<template #suffix>
+											<i
+												class="iconfont el-input__icon login-content-password"
+												:class="state.showPasswdNew ? 'icon-yincangmima' : 'icon-xianshimima'"
+												@click="state.showPasswdNew = !state.showPasswdNew"
+											>
+											</i>
+										</template>
+									</el-input>
+								</el-form-item>
+								<el-form-item
+									label="纭瀵嗙爜"
+									prop="passwordNew2"
+									:rules="[{ validator: validatePassword, required: true, trigger: 'blur' }]"
+								>
+									<el-input :type="state.showPassWdNew2 ? 'text' : 'password'" v-model="state.passwordNew2" autocomplete="off">
+										<template #suffix>
+											<i
+												class="iconfont el-input__icon login-content-password"
+												:class="state.showPassWdNew2 ? 'icon-yincangmima' : 'icon-xianshimima'"
+												@click="state.showPassWdNew2 = !state.showPassWdNew2"
+											>
+											</i>
+										</template>
+									</el-input>
+								</el-form-item>
+								<el-form-item>
+									<el-button icon="ele-Refresh" @click="resetPassword">閲� 缃�</el-button>
+									<el-button icon="ele-SuccessFilled" type="primary" @click="submitPassword">纭� 瀹�</el-button>
+								</el-form-item>
+							</el-form>
+						</el-tab-pane>
+					</el-tabs>
+				</el-card>
+			</el-col>
+		</el-row>
+	</div>
+</template>
+
+<script lang="ts" setup name="sysUserCenter">
+import { onMounted, watch, reactive, ref, nextTick } from 'vue';
+import { storeToRefs } from 'pinia';
+import { ElForm, ElMessage, ElMessageBox, genFileId } from 'element-plus';
+import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus';
+import { useUserInfo } from '/@/stores/userInfo';
+// import { base64ToFile } from '/@/utils/base64Conver';
+// import CropperDialog from '/@/components/cropper/index.vue';
+import { ADMIN_TYPE_MAP } from '/@/views/types';
+import { clearAccessTokens, userInfoKey } from '/@/utils/request';
+import { ResetSystemLoginPwd, UpdateSystemLoginPwd } from '/@/api/auth/userManage';
+import { SERVE_URL } from '/@/constants';
+import { Local } from '/@/utils/storage';
+
+const stores = useUserInfo();
+const { userInfos } = storeToRefs(stores);
+const uploadSignRef = ref<UploadInstance>();
+//const uploadAvatarRef = ref<UploadInstance>();
+const ruleFormBaseRef = ref<InstanceType<typeof ElForm>>();
+const ruleFormPasswordRef = ref<InstanceType<typeof ElForm>>();
+const state = reactive({
+	loading: false,
+	avatarLoading: false,
+	signDialogVisible: false,
+	ruleFormBase: {},
+	ruleFormPassword: {} as any,
+	showPasswdNew: false,
+	showPassWdNew2: false,
+
+	signFileList: [] as any,
+	passwordNew2: '',
+	cropperTitle: '',
+});
+const userInformationInfo = ref({}) as any;
+
+onMounted(async () => {
+	state.loading = true;
+	userInformationInfo.value = Local.get(userInfoKey);
+
+	// var res = await getAPI(SysUserApi).apiSysUserBaseInfoGet();
+	// state.ruleFormBase = res.data.result ?? { account: '' };
+	state.loading = false;
+});
+
+// 涓婁紶澶村儚鍥剧墖
+const uploadCropperImg = async (e: any) => {
+	// var res = await getAPI(SysFileApi).apiSysFileUploadAvatarPostForm(e.img);
+	// userInfos.value.avatar = res.data.result?.filePath + '/' + res.data.result?.name;
+};
+
+// 鑾峰緱鐢靛瓙绛惧悕鏂囦欢鍒楄〃
+const handleChangeSignFile = (_file: any, fileList: []) => {
+	state.signFileList = fileList;
+};
+
+// 瀵嗙爜楠岃瘉
+const validatePassword = (_rule: any, value: any, callback: any) => {
+	if (!state.ruleFormPassword.passwordNew) {
+		callback('璇峰厛杈撳叆鏂板瘑鐮侊紒');
+	} else if (state.passwordNew2 != state.ruleFormPassword.passwordNew) {
+		callback(new Error('涓ゆ瀵嗙爜涓嶄竴鑷达紒'));
+	} else {
+		callback();
+	}
+};
+
+// 瀵嗙爜閲嶇疆
+const resetPassword = () => {
+	ElMessageBox.confirm('纭畾閲嶇疆褰撳墠鐢ㄦ埛瀵嗙爜锛�', '鎻愮ず', {
+		confirmButtonText: '纭畾',
+		cancelButtonText: '鍙栨秷',
+		type: 'warning',
+	})
+		.then(async () => {
+			resetSystemLoginPwd();
+		})
+		.catch(() => {});
+};
+
+const confirmReLogin = () => {
+	// 閫�鍑虹郴缁�
+	ElMessageBox.confirm('瀵嗙爜宸蹭慨鏀癸紝鏄惁閲嶆柊鐧诲綍绯荤粺锛�', '鎻愮ず', {
+		confirmButtonText: '纭畾',
+		cancelButtonText: '鍙栨秷',
+		type: 'warning',
+	})
+		.then(async () => {
+			clearAccessTokens();
+		})
+		.catch(() => {});
+};
+
+const resetSystemLoginPwd = async () => {
+	const res = await ResetSystemLoginPwd({
+		ID: userInfos.value?.User?.LoginAccount?.ID,
+	});
+
+	if (res?.Code === 0) {
+		if (res.Data) {
+			confirmReLogin();
+		} else {
+			ElMessage.error('閲嶇疆瀵嗙爜澶辫触');
+		}
+	} else {
+		ElMessage.error('閲嶇疆瀵嗙爜澶辫触' + (res?.Message ? `锛�${JSON.stringify(res.Message)}` : ''));
+	}
+};
+
+// 瀵嗙爜鎻愪氦
+const submitPassword = () => {
+	ruleFormPasswordRef.value?.validate(async (valid: boolean) => {
+		if (!valid) return;
+		ElMessageBox.confirm('纭畾淇敼褰撳墠璐︽埛瀵嗙爜锛�', '鎻愮ず', {
+			confirmButtonText: '纭畾',
+			cancelButtonText: '鍙栨秷',
+			type: 'warning',
+		})
+			.then(async () => {
+				const res = await UpdateSystemLoginPwd({
+					ID: userInfos.value?.User?.LoginAccount?.ID,
+					LoginPwd: state.passwordNew2,
+				});
+
+				if (res?.Code === 0) {
+					if (res.Data) {
+						confirmReLogin();
+					} else {
+						ElMessage.error('淇敼瀵嗙爜澶辫触');
+					}
+				} else {
+					ElMessage.error('淇敼瀵嗙爜澶辫触' + (res?.Message ? `锛�${JSON.stringify(res.Message)}` : ''));
+				}
+			})
+			.catch(() => {});
+	});
+};
+
+
+
+
+
+const bindingCodeShow = ref(false);
+const wechatQrRef = ref<HTMLIFrameElement>();
+
+const openWechatLogin = async () => {
+	bindingCodeShow.value = true;
+	await nextTick();
+	if (!wechatQrRef.value) return;
+	const url = `${SERVE_URL}JJJHHH/home?isWxLogin=N`;
+	const appid = 'wx4ea2dca37170074c';
+	const state = (new Date().getTime() / 1000).toString();
+	const base64 = btoa(`
+	.impowerBox .title {display:none;}
+
+	.impowerBox .status.status_browser  p:nth-of-type(2){
+		display: none;
+	}
+
+	.impowerBox .qrcode {
+	width: 160px;
+	margin-top:0;
+
+	}
+
+	.info{
+		display: none;
+	}
+	.impowerBox .status{
+	}
+	#tpl_for_iframe{
+		height:100%;
+		overflow: hidden;
+
+		    display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+	}
+	
+	`);
+	const wechatAuthUrl = `https://open.weixin.qq.com/connect/qrconnect?appid=${appid}&redirect_uri=${encodeURIComponent(
+		`http://apiv3.xpump.net/User/wxUserLoginCB.html?from=wi&url=${url}`
+	)}&response_type=code&scope=snsapi_login&state=${state}&href=data:text/css;base64,${base64}#wechat_redirect`;
+	wechatQrRef.value.src = wechatAuthUrl;
+};
+
+// 鎵撳紑瑁佸壀寮圭獥
+const openCropperDialog = () => {
+	// state.cropperTitle = '鏇存崲澶村儚';
+	// cropperDialogRef.value?.openDialog(userInfos.value.avatar);
+};
+
+// 榧犳爣杩涘叆鍜岀寮�澶村儚鏃�
+const mouseEnterAvatar = () => {
+	state.avatarLoading = true;
+};
+
+const mouseLeaveAvatar = () => {
+	state.avatarLoading = false;
+};
+
+// 瀵煎嚭瀵硅薄
+defineExpose({ handleChangeSignFile });
+</script>
+
+<style lang="scss" scoped>
+.login-content-password {
+	display: inline-block;
+	width: 20px;
+	cursor: pointer;
+
+	&:hover {
+		color: #909399;
+	}
+}
+.user-simple-info {
+	display: flex;
+	align-items: flex-start;
+}
+.account-center-avatarHolder {
+	text-align: center;
+	margin-bottom: 24px;
+
+	.username {
+		font-size: 20px;
+		line-height: 28px;
+		font-weight: 500;
+		margin-bottom: 4px;
+	}
+}
+.account-center-org {
+	margin-bottom: 8px;
+	position: relative;
+	p {
+		margin-top: 10px;
+	}
+	span {
+		// padding-left: 17px;
+	}
+}
+.avatar {
+	margin: 0 auto;
+	width: 104px;
+	height: 104px;
+	margin-bottom: 20px;
+	border-radius: 50%;
+	overflow: hidden;
+	img {
+		height: 100%;
+		width: 100%;
+	}
+}
+
+.image-signature {
+	margin-top: 20px;
+	margin-bottom: 10px;
+	width: 100%;
+	height: 150px;
+	background-color: #fff;
+	text-align: center;
+	vertical-align: middle;
+	border: solid 1px var(--el-border-color);
+}
+</style>

--
Gitblit v1.9.3