chenyc
2025-09-23 afa0ffca1673eb61c27496b9988fa8559678bd94
gx用户管理
9个文件已修改
7个文件已添加
1023 ■■■■■ 已修改文件
.env.production 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/register/index.ts 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/i18n/lang/zh-cn.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/navBars/topBar/user.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/upgrade/index.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.ts 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/route.ts 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personal/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/register/index.vue 272 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/registerSuu/index.vue 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/userAdmin/component/addUser.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/userAdmin/component/editUser.vue 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/userAdmin/index.vue 179 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.production
@@ -2,4 +2,4 @@
ENV = production
# 线上环境接口地址
VITE_API_URL = 'https://hemobs.icoldchain.cn/'
VITE_API_URL = 'https://backend.ihemodialysis.com/'
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",
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",
src/api/register/index.ts
New file
@@ -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,
    });
}
src/assets/logo.png
src/i18n/lang/zh-cn.ts
@@ -72,6 +72,7 @@
        visualizingLinkDemo2: '数据可视化演示2',
        personal: '个人中心',
        tongji:'患者健康服务统计',
        userAdmin:'用户管理',
        xueqingdanbai:'质控-血清蛋白控制率',
        tools: '工具类集合',
        layoutLinkView: '外链',
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>
src/layout/upgrade/index.vue
@@ -92,6 +92,7 @@
        }
        .el-dialog__header {
            display: none !important;
            background: red;
        }
        .upgrade-title {
            text-align: center;
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();
    }
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` 路由数组中
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">
src/views/register/index.vue
New file
@@ -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>
src/views/registerSuu/index.vue
New file
@@ -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>
src/views/userAdmin/component/addUser.vue
New file
@@ -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>
src/views/userAdmin/component/editUser.vue
New file
@@ -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>
src/views/userAdmin/index.vue
New file
@@ -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>