From afa0ffca1673eb61c27496b9988fa8559678bd94 Mon Sep 17 00:00:00 2001
From: chenyc <501753378@qq.com>
Date: 星期二, 23 九月 2025 16:55:15 +0800
Subject: [PATCH] gx用户管理

---
 src/assets/logo.png                        |    0 
 src/layout/navBars/topBar/user.vue         |    2 
 package-lock.json                          |   64 +++
 src/views/userAdmin/component/addUser.vue  |  202 +++++++++++
 src/views/userAdmin/index.vue              |  179 +++++++++
 src/api/register/index.ts                  |   62 +++
 src/i18n/lang/zh-cn.ts                     |    1 
 src/router/route.ts                        |   42 ++
 src/views/registerSuu/index.vue            |   26 +
 package.json                               |    1 
 src/views/register/index.vue               |  272 +++++++++++++++
 .env.production                            |    2 
 src/layout/upgrade/index.vue               |    1 
 src/router/index.ts                        |    3 
 src/views/personal/index.vue               |    2 
 src/views/userAdmin/component/editUser.vue |  164 +++++++++
 16 files changed, 1,018 insertions(+), 5 deletions(-)

diff --git a/.env.production b/.env.production
index 270412d..b58c100 100644
--- a/.env.production
+++ b/.env.production
@@ -2,4 +2,4 @@
 ENV = production
 
 # 线上环境接口地址
-VITE_API_URL = 'https://hemobs.icoldchain.cn/'
\ No newline at end of file
+VITE_API_URL = 'https://backend.ihemodialysis.com/'
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 2bd7a23..9adb600 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -36,6 +36,7 @@
 				"screenfull": "^6.0.2",
 				"sortablejs": "^1.15.2",
 				"splitpanes": "^3.1.5",
+				"vant": "^4.9.21",
 				"vue": "^3.4.21",
 				"vue-clipboard3": "^2.0.0",
 				"vue-demi": "^0.14.7",
@@ -1372,6 +1373,21 @@
 			},
 			"peerDependencies": {
 				"@uppy/core": "^2.3.3"
+			}
+		},
+		"node_modules/@vant/popperjs": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmmirror.com/@vant/popperjs/-/popperjs-1.3.0.tgz",
+			"integrity": "sha512-hB+czUG+aHtjhaEmCJDuXOep0YTZjdlRR+4MSmIFnkCQIxJaXLQdSsR90XWvAI2yvKUI7TCGqR8pQg2RtvkMHw==",
+			"license": "MIT"
+		},
+		"node_modules/@vant/use": {
+			"version": "1.6.0",
+			"resolved": "https://registry.npmmirror.com/@vant/use/-/use-1.6.0.tgz",
+			"integrity": "sha512-PHHxeAASgiOpSmMjceweIrv2AxDZIkWXyaczksMoWvKV2YAYEhoizRuk/xFnKF+emUIi46TsQ+rvlm/t2BBCfA==",
+			"license": "MIT",
+			"peerDependencies": {
+				"vue": "^3.0.0"
 			}
 		},
 		"node_modules/@vitejs/plugin-vue": {
@@ -4297,6 +4313,26 @@
 				"base64-arraybuffer": "^1.0.2"
 			}
 		},
+		"node_modules/vant": {
+			"version": "4.9.21",
+			"resolved": "https://registry.npmmirror.com/vant/-/vant-4.9.21.tgz",
+			"integrity": "sha512-hXUoZMrLLjykimFRLDlGNd+K2iYSRh9YwLMKnsVdVZ+9inUKxpqnjhOqlZwocbnYkvJlS+febf9u9aJpDol4Pw==",
+			"license": "MIT",
+			"dependencies": {
+				"@vant/popperjs": "^1.3.0",
+				"@vant/use": "^1.6.0",
+				"@vue/shared": "^3.5.17"
+			},
+			"peerDependencies": {
+				"vue": "^3.0.0"
+			}
+		},
+		"node_modules/vant/node_modules/@vue/shared": {
+			"version": "3.5.21",
+			"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.21.tgz",
+			"integrity": "sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==",
+			"license": "MIT"
+		},
 		"node_modules/vite": {
 			"version": "5.1.6",
 			"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.6.tgz",
@@ -5449,6 +5485,17 @@
 				"@uppy/utils": "^4.1.2",
 				"nanoid": "^3.1.25"
 			}
+		},
+		"@vant/popperjs": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmmirror.com/@vant/popperjs/-/popperjs-1.3.0.tgz",
+			"integrity": "sha512-hB+czUG+aHtjhaEmCJDuXOep0YTZjdlRR+4MSmIFnkCQIxJaXLQdSsR90XWvAI2yvKUI7TCGqR8pQg2RtvkMHw=="
+		},
+		"@vant/use": {
+			"version": "1.6.0",
+			"resolved": "https://registry.npmmirror.com/@vant/use/-/use-1.6.0.tgz",
+			"integrity": "sha512-PHHxeAASgiOpSmMjceweIrv2AxDZIkWXyaczksMoWvKV2YAYEhoizRuk/xFnKF+emUIi46TsQ+rvlm/t2BBCfA==",
+			"requires": {}
 		},
 		"@vitejs/plugin-vue": {
 			"version": "5.0.4",
@@ -7611,6 +7658,23 @@
 				"base64-arraybuffer": "^1.0.2"
 			}
 		},
+		"vant": {
+			"version": "4.9.21",
+			"resolved": "https://registry.npmmirror.com/vant/-/vant-4.9.21.tgz",
+			"integrity": "sha512-hXUoZMrLLjykimFRLDlGNd+K2iYSRh9YwLMKnsVdVZ+9inUKxpqnjhOqlZwocbnYkvJlS+febf9u9aJpDol4Pw==",
+			"requires": {
+				"@vant/popperjs": "^1.3.0",
+				"@vant/use": "^1.6.0",
+				"@vue/shared": "^3.5.17"
+			},
+			"dependencies": {
+				"@vue/shared": {
+					"version": "3.5.21",
+					"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.21.tgz",
+					"integrity": "sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw=="
+				}
+			}
+		},
 		"vite": {
 			"version": "5.1.6",
 			"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.6.tgz",
diff --git a/package.json b/package.json
index 16135ba..0ec6829 100644
--- a/package.json
+++ b/package.json
@@ -38,6 +38,7 @@
 		"screenfull": "^6.0.2",
 		"sortablejs": "^1.15.2",
 		"splitpanes": "^3.1.5",
+		"vant": "^4.9.21",
 		"vue": "^3.4.21",
 		"vue-clipboard3": "^2.0.0",
 		"vue-demi": "^0.14.7",
diff --git a/src/api/register/index.ts b/src/api/register/index.ts
new file mode 100644
index 0000000..178abcf
--- /dev/null
+++ b/src/api/register/index.ts
@@ -0,0 +1,62 @@
+import request from "/@/utils/request";
+export function sendValidateCode(params: any) {
+	return request({
+		url: '/user/info/sendValidateCodeForRegister',
+		method: 'post',
+        headers: {
+            'Content-Type': 'application/x-www-form-urlencoded'
+        },
+		data:params,
+	});
+}
+export function registerForNutrition(params: any) {
+	return request({
+		url: '/user/info/registerForNutrition',
+		method: 'post',
+        headers: {
+            'Content-Type': 'application/json'
+        },
+		data: params,
+	});
+}
+export function listForNutrition(params: any) {
+	return request({
+		url: '/user/info/listForNutrition',
+		method: 'post',
+        headers: {
+            'Content-Type': 'application/json'
+        },
+		data: params,
+	});
+}
+export function Add(params: string) {
+	return request({
+		url: '/user/info/add',
+		method: 'post',
+		data: params,
+	});
+}
+export function update(params: string) {
+	return request({
+		url: '/user/info/update',
+		method: 'post',
+		data: params,
+	});
+}
+export function deleteId(params: string) {
+	return request({
+		url: '/user/info/delete',
+		method: 'post',
+        headers: {
+            'Content-Type': 'application/x-www-form-urlencoded'
+        },
+		data: params,
+	});
+}
+export function getClientList(params: object) {
+	return request({
+		url: '/client/info/list',
+		method: 'post',
+		params,
+	});
+}
\ No newline at end of file
diff --git a/src/assets/logo.png b/src/assets/logo.png
new file mode 100644
index 0000000..7e585df
--- /dev/null
+++ b/src/assets/logo.png
Binary files differ
diff --git a/src/i18n/lang/zh-cn.ts b/src/i18n/lang/zh-cn.ts
index 8ce86df..434bb94 100644
--- a/src/i18n/lang/zh-cn.ts
+++ b/src/i18n/lang/zh-cn.ts
@@ -72,6 +72,7 @@
 		visualizingLinkDemo2: '数据可视化演示2',
 		personal: '个人中心',
 		tongji:'患者健康服务统计',
+		userAdmin:'用户管理',
 		xueqingdanbai:'质控-血清蛋白控制率',
 		tools: '工具类集合',
 		layoutLinkView: '外链',
diff --git a/src/layout/navBars/topBar/user.vue b/src/layout/navBars/topBar/user.vue
index fa73b14..9d15a75 100644
--- a/src/layout/navBars/topBar/user.vue
+++ b/src/layout/navBars/topBar/user.vue
@@ -92,7 +92,7 @@
 					<!-- <el-dropdown-item command="wareHouse">{{ $t('message.user.dropdown6') }}</el-dropdown-item> -->
 					<el-dropdown-item command="/personal">{{ $t('message.user.dropdown2') }}</el-dropdown-item>
 					<el-dropdown-item command="/tongji">患者健康服务统计</el-dropdown-item>
-					<!-- <el-dropdown-item command="/401">{{ $t('message.user.dropdown4') }}</el-dropdown-item> -->
+					<el-dropdown-item command="/userAdmin">用户管理</el-dropdown-item>
 					<el-dropdown-item divided command="logOut">{{ $t('message.user.dropdown5') }}</el-dropdown-item>
 				</el-dropdown-menu>
 			</template>
diff --git a/src/layout/upgrade/index.vue b/src/layout/upgrade/index.vue
index c94eb9c..ac198ab 100644
--- a/src/layout/upgrade/index.vue
+++ b/src/layout/upgrade/index.vue
@@ -92,6 +92,7 @@
 		}
 		.el-dialog__header {
 			display: none !important;
+			background: red;
 		}
 		.upgrade-title {
 			text-align: center;
diff --git a/src/router/index.ts b/src/router/index.ts
index e33cef8..ad85cdc 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -92,13 +92,14 @@
 
 // 路由加载前
 router.beforeEach(async (to, from, next) => {
+	console.log('to', to);
 	NProgress.configure({ showSpinner: false });
 	if (to.meta.title) NProgress.start();
 	const token = Session.get('token');
 	if (to.path === '/login' && !token) {
 		next();
 		NProgress.done();
-	}else if (to.path === '/tiaochabiao1' && !token) {
+	}else if ((to.path === '/register'||to.path==='/registerSuu') && !token) {
 		next();
 		NProgress.done();
 	}
diff --git a/src/router/route.ts b/src/router/route.ts
index d4258de..d9f0b2e 100644
--- a/src/router/route.ts
+++ b/src/router/route.ts
@@ -1135,6 +1135,21 @@
 				},
 			},
 			{
+				path: '/userAdmin',
+				name: 'userAdmin',
+				component: () => import('/@/views/userAdmin/index.vue'),
+				meta: {
+					title: 'message.router.userAdmin',
+					isLink: '',
+					isHide: false,
+					isKeepAlive: true,
+					isAffix: false,
+					isIframe: false,
+					roles: ['admin', 'common'],
+					icon: 'iconfont icon-gerenzhongxin',
+				},
+			},
+			{
 				path: '/zhikong/xueqingdanbai',
 				name: 'xueqingdanbai',
 				component: () => import('/@/views/zhikong/xueqingdanbai.vue'),
@@ -1346,7 +1361,15 @@
 			},
 		],
 
-	}
+	},
+	{
+		path: '/register',
+		name: 'register',
+		component: () => import('/@/views/register/index.vue'),
+		meta: {
+			title: '注册',
+		},
+	},
 ];
 
 /**
@@ -1380,6 +1403,22 @@
 			title: '调查表',
 		},
 	},
+	{
+		path: '/register',
+		name: 'register',
+		component: () => import('/@/views/register/index.vue'),
+		meta: {
+			title: '注册',
+		},
+	},
+	{
+		path: '/registerSuu',
+		name: 'registerSuu',
+		component: () => import('/@/views/registerSuu/index.vue'),
+		meta: {
+			title: '注册成功',
+		},
+	},
 ];
 
 /**
@@ -1397,6 +1436,7 @@
 			title: '登录',
 		},
 	},
+	
 	/**
 	 * 提示:写在这里的为全屏界面,不建议写在这里
 	 * 请写在 `dynamicRoutes` 路由数组中
diff --git a/src/views/personal/index.vue b/src/views/personal/index.vue
index 69980dc..e4db217 100644
--- a/src/views/personal/index.vue
+++ b/src/views/personal/index.vue
@@ -12,7 +12,7 @@
 						</div>
 						<div class="personal-user-right">
 							<el-row>
-								<el-col :span="24" class="personal-title mb18">{{ currentTime }},admin,生活变的再糟糕,也不妨碍我变得更好! </el-col>
+								<!-- <el-col :span="24" class="personal-title mb18">{{ currentTime }},admin,生活变的再糟糕,也不妨碍我变得更好! </el-col> -->
 								<el-col :span="24">
 									<el-row>
 										<el-col :xs="24" :sm="8" class="personal-item mb6">
diff --git a/src/views/register/index.vue b/src/views/register/index.vue
new file mode 100644
index 0000000..cab0e0d
--- /dev/null
+++ b/src/views/register/index.vue
@@ -0,0 +1,272 @@
+<template>
+  <div class="register-form">
+    <!-- Logo -->
+    <el-image :src="logo" :width="100" :height="100" />
+    <h1>用户注册</h1>
+    <p class="desc">创建您的账户,开始使用我们的服务</p>
+
+    <!-- 表单 -->
+    <el-form
+      :model="formData"
+      :rules="formRules"
+      ref="formRef"
+      @submit.prevent="onSubmit"
+      label-width="auto"
+      class="form-container"
+    >
+      <!-- 用户名 -->
+      <el-form-item label="用户姓名*" prop="username">
+        <el-input
+          v-model="formData.username"
+          placeholder="请输入您的姓名"
+        />
+      </el-form-item>
+
+      <!-- 手机号 -->
+      <el-form-item label="手机号*" prop="phone">
+        <el-input
+          v-model="formData.phone"
+          placeholder="请输入您的手机号"
+        />
+      </el-form-item>
+
+      <!-- 验证码 -->
+      <el-form-item label="手机验证码*" prop="code">
+        <el-input
+          v-model="formData.code"
+          placeholder="请输入验证码"
+          class="code-input"
+        >
+          <template #append>
+            <el-button
+              type="primary"
+              @click="sendCode"
+              :disabled="isSendingCode"
+            >
+              {{ sendButtonText }}
+            </el-button>
+          </template>
+        </el-input>
+      </el-form-item>
+
+      <!-- 邮箱 -->
+      <el-form-item label="邮箱地址*" prop="email">
+        <el-input
+          v-model="formData.email"
+          type="email"
+          placeholder="请输入您的邮箱地址"
+        />
+      </el-form-item>
+
+      <!-- 密码 -->
+      <el-form-item label="密码*" prop="password">
+        <el-input
+          v-model="formData.password"
+          type="password"
+          placeholder="请输入您的密码"
+        />
+      </el-form-item>
+
+      <!-- 确认密码 -->
+      <el-form-item label="确认密码*" prop="confirmPassword">
+        <el-input
+          v-model="formData.confirmPassword"
+          type="password"
+          placeholder="请确认您的密码"
+        />
+      </el-form-item>
+
+      <!-- 提交按钮 -->
+      <div class="submit-btn">
+        <el-button
+          round
+          type="primary"
+          native-type="submit"
+          :loading="submitLoading"
+          style="width: 100%"
+        >
+          立即注册
+        </el-button>
+      </div>
+    </el-form>
+
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue';
+import { useRouter } from 'vue-router';
+import { ElMessage, ElLoading } from 'element-plus';
+import logo from '/@/assets/logo.png';
+
+// API 导入(保持不变)
+import { sendValidateCode, registerForNutrition } from "/@/api/register";
+
+const router = useRouter();
+
+// 表单数据
+const formData = reactive({
+  username: '',
+  phone: '',
+  code: '',
+  email: '',
+  password: '',
+  confirmPassword: ''
+});
+
+// 表单引用(用于校验)
+const formRef = ref(null);
+
+// 提交加载状态
+const submitLoading = ref(false);
+
+// 验证码发送状态
+const isSendingCode = ref(false);
+const sendButtonText = ref('发送验证码');
+let countdownTimer = null;
+const countdown = ref(60);
+
+// 手机号格式校验
+const isValidPhone = (phone) => /^1[3456789]\d{9}$/.test(phone);
+
+// 发送验证码
+const sendCode = () => {
+  if (!formData.phone) {
+    ElMessage.error('请先填写手机号');
+    return;
+  }
+
+  if (!isValidPhone(formData.phone)) {
+    ElMessage.error('请输入正确的手机号码');
+    return;
+  }
+
+  // 模拟请求发送验证码
+  console.log('发送验证码至:', formData.phone);
+  sendValidateCode('mobileNo=' + formData.phone)
+    .then(() => {
+      ElMessage.success('验证码已发送');
+      // 启动倒计时
+      isSendingCode.value = true;
+      countdown.value = 60;
+      sendButtonText.value = `${countdown.value}秒后重发`;
+
+      countdownTimer = setInterval(() => {
+        countdown.value--;
+        sendButtonText.value = `${countdown.value}秒后重发`;
+        if (countdown.value <= 0) {
+          clearInterval(countdownTimer);
+          isSendingCode.value = false;
+          sendButtonText.value = '重新发送';
+        }
+      }, 1000);
+    })
+    .catch(() => {
+      ElMessage.error('验证码发送失败');
+    });
+};
+
+// 自定义密码确认校验
+const validatePass = (rule, value, callback) => {
+  if (value !== formData.password) {
+    callback(new Error('两次输入密码不一致'));
+  } else {
+    callback();
+  }
+};
+
+// 表单规则
+const formRules = {
+  username: [
+    { required: true, message: '请填写用户名', trigger: 'blur' }
+  ],
+  phone: [
+    { required: true, message: '请填写手机号', trigger: 'blur' },
+    { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
+  ],
+  code: [
+    { required: true, message: '请填写验证码', trigger: 'blur' }
+  ],
+  email: [
+    { pattern: /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/, message: '请输入正确的邮箱格式', trigger: 'blur' }
+  ],
+  password: [
+    { required: true, message: '请填写密码', trigger: 'blur' },
+    { min: 6, message: '密码长度不能少于6位', trigger: 'blur' }
+  ],
+  confirmPassword: [
+    { required: true, message: '请确认密码', trigger: 'blur' },
+    { validator: validatePass, trigger: 'blur' }
+  ]
+};
+
+// 表单提交
+const onSubmit = () => {
+  formRef.value.validate(async (valid) => {
+    if (!valid) return;
+
+    const submitData = {
+      手机验证码: formData.code,
+      用户姓名: formData.username,
+      手机号: formData.phone,
+      密码: formData.confirmPassword,
+      Email: formData.email
+    };
+
+    console.log('提交数据:', submitData);
+
+    const loading = ElLoading.service({
+      lock: true,
+      text: '注册中...',
+      background: 'rgba(0, 0, 0, 0.7)'
+    });
+
+    try {
+      const res = await registerForNutrition(submitData);
+      if (res.code === 400) {
+        ElMessage.error(res.message);
+      } else if (res.code === 200) {
+        ElMessage.success('注册成功!');
+        router.push('/registerSuu');
+      }
+    } catch (err) {
+      ElMessage.error('注册失败,请稍后重试');
+    } finally {
+      loading.close();
+    }
+  });
+};
+</script>
+
+<style scoped>
+.register-form {
+  text-align: center;
+  max-width: 400px;
+  margin: 0 auto;
+  padding: 20px;
+  padding-top: 40px;
+}
+
+h1 {
+  font-size: 20px;
+  margin-bottom: 10px;
+}
+
+.desc {
+  color: #666;
+  font-size: 14px;
+  margin-bottom: 20px;
+}
+
+.form-container {
+  margin-top: 20px;
+}
+
+.code-input :deep(.el-input-group__append) {
+  padding: 0;
+}
+
+.submit-btn {
+  margin: 24px 0;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/registerSuu/index.vue b/src/views/registerSuu/index.vue
new file mode 100644
index 0000000..7f05019
--- /dev/null
+++ b/src/views/registerSuu/index.vue
@@ -0,0 +1,26 @@
+<template>
+    <div class="success-container" style="text-align: center;margin-top: 100px;">
+        <el-image :src="logo" :width="100" :height="100" style="margin-bottom: 30px;" />
+      <van-icon name="checked" class="success-icon" />
+      <h2>注册成功!</h2>
+      <p>您的账户已成功创建,欢迎加入我们!</p>
+      <p>待审核通过后才可以登录系统!</p>
+      <!-- <van-button type="primary" block @click="goToLogin">前往登录</van-button> -->
+    </div>
+</template>
+<script setup>
+  import logo from '/@/assets/logo.png';
+</script>
+<style scoped>
+
+  .success-icon {
+    font-size: 60px;
+    color: #4caf50;
+    margin-bottom: 20px;
+  }
+p {
+    height: 40px;
+    line-height: 40px;
+  font-size: 14px;
+}
+  </style>
\ No newline at end of file
diff --git a/src/views/userAdmin/component/addUser.vue b/src/views/userAdmin/component/addUser.vue
new file mode 100644
index 0000000..d96ad0d
--- /dev/null
+++ b/src/views/userAdmin/component/addUser.vue
@@ -0,0 +1,202 @@
+<template>
+	<div class="system-add-user-container">
+		<div v-if="isShowDialog">
+				<el-dialog title="新增用户" v-model="isShowDialog" width="769px">
+				<el-form :model="ruleForm" :rules="rules" ref="adduserForm" size="small" label-width="90px">
+					<el-row :gutter="35">
+						
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="用户代号" prop="userNo">
+								<el-input v-model="ruleForm.userNo"  placeholder="请输入用户代号" clearable></el-input>
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="用户姓名" prop="userName">
+								<el-input v-model="ruleForm.userName" placeholder="请输入用户姓名" clearable></el-input>
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="手机号" prop="userMobile">
+								<el-input v-model="ruleForm.userMobile" placeholder="请输入手机号" clearable></el-input>
+							</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 v-model="ruleForm.userEmail" placeholder="请输入" clearable></el-input>
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="his编号">
+								<el-input v-model="ruleForm.hisCode" placeholder="请输入his编号" clearable></el-input>
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="性别">
+								<el-select clearable  v-model="ruleForm.userGender" placeholder="请选择"  class="w100">
+									<el-option label="男" :value="0"></el-option>
+									<el-option label="女" :value="1"></el-option>
+								</el-select>
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="账户过期">
+								<el-date-picker v-model="ruleForm.updateTime" type="date" placeholder="请选择" class="w100"> </el-date-picker>
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+							<el-form-item label="用户状态">
+								<el-switch v-model="ruleForm.isValid" inline-prompt :active-value="1" :inactive-value="0" active-text="启" inactive-text="禁"></el-switch>
+							</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-number v-model="ruleForm.userSortOrder"  /> -->
+							<el-input v-model.number="ruleForm.userSortOrder" type="number" oninput="value=value.replace(/[^\d]/g,'')" placeholder="请输入"></el-input>
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+							<el-form-item label="角色分配">
+								<el-checkbox-group v-model="checkedRoles" >
+									<el-checkbox v-for="(role,index) in roleData" :disabled='role.roleName==="admin"' :key="index" :label="role.roleText">{{role.roleText}}</el-checkbox>
+								</el-checkbox-group>
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+							<el-form-item label="用户描述">
+								<el-input v-model="ruleForm.remark" type="textarea" placeholder="请输入用户描述" maxlength="150"></el-input>
+							</el-form-item>
+						</el-col>
+					</el-row>
+				</el-form>
+				<template #footer>
+					<span class="dialog-footer">
+						<el-button @click="onCancel" :loading="loading" size="small">取 消</el-button>
+						<el-button type="primary" :loading="loading" @click="onSubmit" size="small">新 增</el-button>
+					</span>
+				</template>
+			</el-dialog>
+		</div>
+	</div>
+</template>
+
+<script lang="ts">
+import { reactive, toRefs, onMounted,getCurrentInstance} from 'vue';
+import {Add } from '/@/api/user/index'
+import { useStore } from '/@/store/index';
+import {list as getroleList} from '/@/api/role/index'
+export default {
+	name: 'systemAddUser',
+	setup(props,context) {
+		const { proxy } = getCurrentInstance() as any;
+		const store = useStore();
+		const state = reactive({
+			isShowDialog: false,
+			ruleForm: {
+				id:0,
+				userName: '', // 账户名称
+				userNo: '', // 用户昵称
+				roleSign: '', // 关联角色
+				userMobile: '', // 手机号
+				userEmail: '', // 邮箱
+				userGender: 0, // 性别
+				userTitle:'',//职称(编号)
+				overdueTime: '', // 账户过期
+				isValid: 1, // 用户状态
+				remark: '', // 用户描述
+				userSortOrder:0,
+				hisCode:'',
+				roles:[]
+			},
+			rules: {
+				userName: { required: true, message: '请输入用户姓名', trigger: 'blur' },
+				userNo: { required: true, message: '请输入用户代号', trigger: 'blur' },
+				userEmail: { required: true, message: '请输入用户邮箱', trigger: 'blur' },
+				userMobile: [
+					{ required: true, message: '请输入用户手机号码', trigger: 'blur' },
+					{ pattern: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/, message: '请输入有效的手机号', trigger: 'blur' }
+				],
+			},
+			checkedRoles:[],
+			roleData:[], // 部门数据
+			loading: false,
+		});
+		// 打开弹窗
+		const openDialog = () => {
+			state.ruleForm={
+				id:0,
+				userName: '', // 账户名称
+				userNo: '', // 用户昵称
+				roleSign: '', // 关联角色
+				userMobile: '', // 手机号
+				userEmail: '', // 邮箱
+				userGender: 0, // 性别
+				userTitle:'',//职称(编号)
+				overdueTime: '', // 账户过期
+				isValid: 1, // 用户状态
+				remark: '', // 用户描述
+				userSortOrder:999,
+				roles:[]
+			}
+			state.isShowDialog = true;
+		};
+		// 关闭弹窗
+		const closeDialog = () => {
+			state.isShowDialog = false;
+		};
+		// 取消
+		const onCancel = () => {
+			closeDialog();
+		};
+		// 新增
+		const onSubmit = () => {
+			console.log('3434')
+			console.log(state.checkedRoles)
+			proxy.$refs['adduserForm'].validate(async (valid) => {
+				if(valid){
+					state.loading = true;
+					const roles: never[]=[]
+					if(state.checkedRoles.length>0){
+						state.roleData.forEach(r=>{
+							if(state.checkedRoles.findIndex(e=>e===r.roleText)>-1){
+								roles.push({role_code:r.code})
+							}
+						})
+					}
+					state.ruleForm.userVsRoleList=roles
+					state.ruleForm.clientCode=store.state.userInfos.userInfos.client.code
+					Add(state.ruleForm).then(()=>{
+						closeDialog();
+						context.emit("update:Search");//调用父级方法参数
+					}).finally(() => {
+						state.loading = false;
+					})
+				}
+			})
+		};
+		// 初始化部门数据
+		const initTableData = () => {
+			var ps= new Object ({
+				page: 0,
+				size: 0,
+				wherecondition: '',
+				ordercondition: 'create_time desc'
+			})
+			getroleList(ps).then(re=>{
+				state.roleData=re.data.list
+				console.log(state.roleData)
+			})
+		};
+		// 页面加载时
+		onMounted(() => {
+			initTableData();
+		});
+		return {
+			openDialog,
+			closeDialog,
+			onCancel,
+			onSubmit,
+			...toRefs(state),
+		};
+	},
+};
+</script>
diff --git a/src/views/userAdmin/component/editUser.vue b/src/views/userAdmin/component/editUser.vue
new file mode 100644
index 0000000..76db1c2
--- /dev/null
+++ b/src/views/userAdmin/component/editUser.vue
@@ -0,0 +1,164 @@
+<template>
+	<div class="upgrade-dialog">
+		<el-dialog title="修改用户" v-model="isShowDialog" width="1069px" center>
+			<el-form :model="ruleForm" :rules="rules" ref="edituserForm" label-width="90px">
+				<el-row :gutter="35">
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="用户代号" prop="userNo">
+							<el-input v-model="ruleForm.userNo"  placeholder="请输入用户代号" clearable></el-input>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="用户姓名" prop="userName">
+							<el-input v-model="ruleForm.userName"  placeholder="请输入用户姓名" clearable></el-input>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="手机号" prop="userMobile">
+							<el-input v-model="ruleForm.userMobile" placeholder="请输入手机号" clearable></el-input>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="用户状态">
+							<el-switch v-model="ruleForm.isValid" inline-prompt :inactive-value="0" :active-value="1" active-text="启" inactive-text="禁"></el-switch>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="所属医院">
+							<div style="border: 1px solid #EBEDF0;padding: 5px; ">
+								<el-checkbox-group v-model="ruleForm.clientCodes">
+									<el-checkbox v-for="(client,index) in clientData" :label="client.clientName" :value="client.code" :key="index" />
+								</el-checkbox-group>
+							</div>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="用户描述">
+							<el-input v-model="ruleForm.remark" type="textarea" placeholder="请输入用户描述" maxlength="150"></el-input>
+						</el-form-item>
+					</el-col>
+				</el-row>
+			</el-form>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="onCancel" :loading="loading" >取 消</el-button>
+					<el-button type="primary" :loading="loading" @click="onSubmit" >修 改</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts">
+import { reactive, toRefs, onMounted,getCurrentInstance } from 'vue';
+import {update,getClientList} from '/@/api/register'  
+export default {
+	name: 'systemEditUser',
+	setup(props,context) {
+		const { proxy } = getCurrentInstance() as any;
+		const state = reactive({
+			isShowDialog: false,
+			ruleForm: {
+				userName: '', // 账户名称
+				userNo: '', // 用户昵称
+				roleSign: '', // 关联角色
+				userMobile: '', // 手机号
+				userEmail: '', // 邮箱
+				userGender: 0, // 性别
+				userTitle:'',//职称(编号)
+				overdueTime: '', // 账户过期
+				isValid: 0, // 用户状态
+				clientCodes:'',
+				remark: '', // 用户描述
+			
+			},
+
+			clientData: [], // 部门数据
+			rules: {
+				userName: { required: true, message: '请输入用户姓名', trigger: 'blur' },
+				userNo: { required: true, message: '请输入用户代号', trigger: 'blur' },
+				userMobile: [
+					{ required: true, message: '请输入用户手机号码', trigger: 'blur' },
+					{ pattern: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/, message: '请输入有效的手机号', trigger: 'blur' }
+				],
+			},
+			loading: false,
+		});
+		// 打开弹窗
+		const openDialog = (row: any) => {
+			state.ruleForm =row
+			state.isShowDialog = true;
+		};
+		// 关闭弹窗
+		const closeDialog = () => {
+			state.isShowDialog = false;
+		};
+		// 取消
+		const onCancel = () => {
+			closeDialog();
+		};
+		// 新增
+		const onSubmit = () => {
+			proxy.$refs['edituserForm'].validate(async (valid) => {
+				if(valid){
+					state.loading = true;
+					update(state.ruleForm).then(()=>{
+						closeDialog();
+						context.emit("update:Search");//调用父级方法参数
+					}).finally(() => {
+						state.loading = false;
+					})
+				}
+			})
+		};
+		// 初始化部门数据
+		const initTableData = () => {
+			const pas={
+				page: 0,
+				size: 0,
+				wherecondition: '',
+				ordercondition: 'create_time desc'
+			}
+			getClientList(pas).then((res)=>{
+				state.clientData=res.data.list
+				console.log(res.data.list,'部门数据')
+			})
+
+		};
+		// 页面加载时
+		onMounted(() => {
+			initTableData();
+		});
+		return {
+			openDialog,
+			closeDialog,
+			onCancel,
+			onSubmit,
+			...toRefs(state),
+		};
+	},
+};
+</script>
+<style scoped lang="scss">
+.upgrade-dialog {
+	:deep(.el-dialog) {
+		padding:0;
+		padding-bottom: 20px;
+		.el-dialog__body {
+			padding: 5 !important;
+		}
+		.el-dialog__header {
+			background: #409EFF;
+			height: 50px;
+			line-height: 50px;
+			margin-bottom: 30px;
+			.span{
+				color: white;
+			}
+			
+		}
+	
+	}
+}
+</style>
+
diff --git a/src/views/userAdmin/index.vue b/src/views/userAdmin/index.vue
new file mode 100644
index 0000000..6d1db38
--- /dev/null
+++ b/src/views/userAdmin/index.vue
@@ -0,0 +1,179 @@
+<template>
+    <div class="user-management">
+      <!-- 搜索和操作区域 -->
+      <el-form :inline="true" class="demo-form-inline" style="background-color: white;padding-top: 20px; padding-left: 10px;">
+        <el-form-item label="">
+          <el-input v-model="search.userNameOrMobile" placeholder="请输入用户名/手机号"></el-input>
+        </el-form-item>
+        <el-form-item label="用户状态">
+          <el-select v-model="search.isValid" placeholder="请选择用户状态" style="width: 100px;">
+            <el-option label="全部" value=""></el-option>
+            <el-option label="启用" :value="1"></el-option>
+            <el-option label="禁用" :value="0"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="onSearch"> <el-icon><Search /></el-icon>查询</el-button>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="onAddUser"><el-icon><Plus /></el-icon>新增用户</el-button>
+        </el-form-item>
+      </el-form>
+  
+      <!-- 用户列表 -->
+      <el-table :data="tableData" style="width: 100%;background-color: white; min-height: 700px;">
+        <el-table-column prop="userName" label="用户姓名"></el-table-column>
+        <el-table-column prop="userNo" label="登录名"></el-table-column>
+        <el-table-column prop="userMobile" label="手机号"></el-table-column>
+        <el-table-column prop="createTime" label="注册时间"></el-table-column>
+        <el-table-column label="用户状态">
+          <template #default="scope">
+            <el-tag :type="scope.row.isValid === 1 ? 'success' : 'danger'">{{ scope.row.isValid === 1 ? '启用' : '禁用' }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="所属医院">
+          <template #default="scope">
+            <el-tag v-for="hospital in scope.row.clientInfos" :key="hospital" size="small" style="margin-right: 5px;">{{ hospital.clientName }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作">
+          <template #default="scope">
+            <el-button @click="onEdit(scope.$index, scope.row)"><el-icon><Edit /></el-icon></el-button>
+            
+            <el-button  @click="onDelete(scope.$index, scope.row)" style="color: red;"><el-icon><Delete /></el-icon></el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+  
+      <!-- 分页 -->
+      <el-pagination style="margin-top: 20px;"
+        background
+        layout="prev, pager, next"
+        :total="total"
+        @current-change="handleCurrentChange"
+      ></el-pagination>
+      <EditUser ref="editUserRef"  @update:Search="onSearch" />
+    </div>
+  </template>
+  
+  <script>
+  import { onMounted, ref } from 'vue';
+  import { ElLoading, ElMessageBox } from 'element-plus';
+  import {listForNutrition,deleteId} from '/@/api/register'   
+  import EditUser from './component/editUser.vue';
+  export default {
+    components: { EditUser },
+    setup() {
+      const search = ref({
+        userNameOrMobile: '',
+        isValid: '',
+        page:1,
+        size:10
+      });
+      const editUserRef=ref()
+      const tableData = ref([]);
+  
+      const total = ref(1);
+  
+      const onSearch = () => {
+        // 实现搜索逻辑
+        getDatas()
+      };
+  
+      const onAddUser = () => {
+        // 实现新增用户逻辑
+        editUserRef.value.openDialog({
+            id:0,
+            userName:'',
+            userNo:'',
+            userMobile:'',
+            userGender:'',
+            isValid:1,
+            clientCodes:[],
+            remark:''
+        })
+      };
+  
+      const onEdit = (index, row) => {
+        const pasm={
+            id:row.id,
+            userName:row.userName,
+            userNo:row.userNo,
+            userMobile:row.userMobile,
+            userGender:row.userGender,
+            isValid:row.isValid,
+            clientCodes:row.clientInfos.map(item=>item.code),
+            remark:row.remark
+        }
+        console.log(pasm)
+        // 实现编辑逻辑
+        editUserRef.value.openDialog(pasm)
+
+      };
+  
+      const onDelete = (index, row) => {
+        // 实现删除逻辑
+        console.log(row)
+        ElMessageBox.confirm(`确定删除${row.userName}?`, '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
+        }).then(() => {
+            deleteId({id:row.id}).then(res=>{
+                getDatas()
+            })
+        }).catch(() => {
+          // 用户取消删除
+        });
+      };
+  
+      const handleCurrentChange = (currentPage) => {
+        search.value.page = currentPage;    
+        getDatas()
+        // 实现分页逻辑
+      };
+      onMounted(async()=>{
+        getDatas()
+
+      })
+      const getDatas=()=>{
+        const loading = ElLoading.service({
+            lock: true,
+            text: 'Loading',
+            background: 'rgba(0, 0, 0, 0.7)',
+        })
+        listForNutrition(search.value).then(res=>{
+            tableData.value=res.data.list
+            total.value=res.data.total
+            console.log(res)
+
+        }).finally(()=>{
+            loading.close()
+        })  
+      }
+      return {
+        search,
+        tableData,
+        total,
+        onSearch,
+        editUserRef,
+        onAddUser,
+        onEdit,
+        onDelete,
+        handleCurrentChange
+      };
+    }
+  };
+  </script>
+  
+  <style scoped>
+  body {
+    background-color: #8c3e3e;
+  }
+  .user-management {
+    padding: 50px;
+  }
+  .demo-form-inline {
+    margin-bottom: 20px;
+  }
+  </style>
\ No newline at end of file

--
Gitblit v1.8.0