zhuangyunsheng před 1 rokem
rodič
revize
0b481235d3

+ 14 - 31
src/api/system/log.js

@@ -1,6 +1,5 @@
 import request from "@/utils/request";
 import { useUserStore } from "@/store/user";
-const { userInfo } = useUserStore(); // store 用户
 
 export default {
     get: function (params) {
@@ -11,35 +10,19 @@ export default {
         })
     },
 
-    add: function (data) {
-        return request({
-            url: "/qdport-zcgx/log/save",
-            data: {
-                userId: userInfo.id,
-                loginName: userInfo.userName,
-                userName: userInfo.name,
-                // operateName //  新增删除修改
-                // operateType // 政策分享 消息管理
-            }
-        })
-    },
-
-    edit: function (data) {
-        return request({
-            url: "/qdport-zcgx/log/update",
-            method: "post",
-            data
-        })
-    },
-
-    del: function (data) {
-        return request({
-            headers: {
-                "Content-Type": "application/x-www-form-urlencoded"
-            },
-            url: "/qdport-zcgx/log/remove",
-            method: "post",
-            data
-        })
+    add: function (operateName, operateType) {
+        return Promise.all([
+            request({
+                url: "/qdport-zcgx/log/save",
+                method: "post",
+                data: {
+                    userId: useUserStore().userInfo.id,
+                    loginName: useUserStore().userInfo.userName,
+                    userName: useUserStore().userInfo.name,
+                    operateName,
+                    operateType
+                }
+            }).catch(() => ElMessage.warning("日志异常"))
+        ])
     }
 }

+ 12 - 12
src/router/constantRoutes.js

@@ -27,18 +27,18 @@ export const staticRoutes = [
         hidden: true,
         component: () => import("@/views/error/noPermission.vue")
     },
-    {
-        path: "/yh",
-        name: "yhlogin",
-        hidden: true,
-        component: () => import("@/otherLogin/bx.vue"),
-    },
-    {
-        path: "/ssoyh",
-        name: "ssoyh",
-        hidden: true,
-        component: () => import("@/otherLogin/ssoSgzl.vue"),
-    },
+    // {
+    //     path: "/yh",
+    //     name: "yhlogin",
+    //     hidden: true,
+    //     component: () => import("@/otherLogin/bx.vue"),
+    // },
+    // {
+    //     path: "/ssoyh",
+    //     name: "ssoyh",
+    //     hidden: true,
+    //     component: () => import("@/otherLogin/ssoSgzl.vue"),
+    // },
     {
         path: "",
         component: Layout,

+ 1 - 70
src/router/dynamicRoutes.js

@@ -1,73 +1,4 @@
 //暂不启用
 const Layout = () => import('@/layout/index.vue')
 
-export const dynamicRoutes = [
-
-    // {
-    //     path: '/testManage',
-    //     component: Layout,
-    //     redirect: '/test',
-    //     meta: {
-    //         title: '测试',
-    //         icon: 'Box',
-    //     },
-    //     children: [
-    //         {
-    //             path: 'test',
-    //             name: 'Test',
-    //             component: () => import('@/views/test.vue'),
-    //             meta: {
-    //                 title: '测试',
-    //                 icon: 'Box',
-    //             },
-    //         }
-    //     ]
-    // },
-    // {
-    //     path: '/system',
-    //     component: Layout,
-    //     redirect: '/menu',
-    //     meta: {
-    //         title: '平台运维',
-    //         icon: 'Box',
-    //     },
-    //     children: [
-    //         {
-    //             path: 'user',
-    //             name: 'User',
-    //             component: () => import('@/views/system/user.vue'),
-    //             meta: {
-    //                 title: '用户管理',
-    //                 icon: 'Box',
-    //             },
-    //         },
-    //         {
-    //             path: 'dept',
-    //             name: 'Dept',
-    //             component: () => import('@/views/system/dept.vue'),
-    //             meta: {
-    //                 title: '部门管理',
-    //                 icon: 'Box',
-    //             },
-    //         },
-    //         {
-    //             path: 'role',
-    //             name: 'Role',
-    //             component: () => import('@/views/system/role.vue'),
-    //             meta: {
-    //                 title: '角色管理',
-    //                 icon: 'Box',
-    //             },
-    //         },
-    //         {
-    //             path: 'menu',
-    //             name: 'Menu',
-    //             component: () => import('@/views/system/menu.vue'),
-    //             meta: {
-    //                 title: '菜单管理',
-    //                 icon: 'Box',
-    //             },
-    //         }
-    //     ]
-    // }
-]
+export const dynamicRoutes = []

+ 14 - 10
src/store/user.js

@@ -1,4 +1,5 @@
 import { getToken, setToken, removeToken, setRefreshToken, getRefreshToken, removeRefreshToken } from "@/utils/auth"
+import API from "@/api/system/log"
 import { login } from "@/api/login"
 import CryptoJS from "crypto-js"
 const { VITE_BX_CLIENT_ID, VITE_EDGE_CLIENT_ID } = import.meta.env
@@ -56,6 +57,7 @@ export const useUserStore = defineStore(
                             this.refreshToken = res.refresh_token
                             this.menuList = res.menus
                             this.permissions = getButtonPermiss([], res.menus)
+                            API.add("登录", "login_system")
                             resolve()
                         }
                     }).catch(error => {
@@ -137,16 +139,18 @@ export const useUserStore = defineStore(
             },
             // 退出系统
             logOut() {
-                return new Promise((resolve, reject) => {
-                    this.token = ""
-                    this.refreshToken = ""
-                    this.userInfo = {}
-                    this.menuList = []
-                    this.roles = []
-                    this.permissions = []
-                    removeToken()
-                    removeRefreshToken()
-                    resolve()
+                return API.add("退出", "logout_system").then(() => {
+                    new Promise((resolve, reject) => {
+                        this.token = ""
+                        this.refreshToken = ""
+                        this.userInfo = {}
+                        this.menuList = []
+                        this.roles = []
+                        this.permissions = []
+                        removeToken()
+                        removeRefreshToken()
+                        resolve()
+                    })
                 })
             }
         }

+ 5 - 6
src/views/error/noPermission.vue

@@ -1,15 +1,11 @@
 <template>
     <div class="wscn-http404-container">
         <div class="wscn-http404">
-            <!-- <div class="pic-404">
-                <img src="./midheaderlogo.png" alt="" />
-            </div> -->
             <div class="bullshit">
                 <div class="bullshit__oops">该账户无权登录!</div>
-                <!-- <div class="bullshit__headline">该账户无权登录!</div> -->
                 <div class="bullshit__info">对不起,您的账号无权登录系统。请联系系统管理员进行授权。</div>
                 <div class="bullshit__btn">
-                    <div class="bullshit__btn-return-home" id="returnHomeBtn" @click="go">返回重新登</div>
+                    <div class="bullshit__btn-return-home" id="returnHomeBtn" @click="go">返回重新登</div>
                 </div>
             </div>
         </div>
@@ -17,8 +13,11 @@
 </template>
 
 <script setup>
+import router from "@/router";
+import { useUserStore } from "@/store/user";
+
 function go() {
-     window.location.href = "https://cloud.qdpi.net.cn"; 
+    useUserStore().logOut().then(() => router.push("/login"));
 }
 </script>
 

+ 141 - 443
src/views/login/index.vue

@@ -1,488 +1,186 @@
 <template>
-    <div class="tjm_login">
-        <el-carousel height="100vh" :pause-on-hover="false">
-            <el-carousel-item>
-                <img src="@/assets/images/welcomebg1.png" alt="" />
-            </el-carousel-item>
-            <el-carousel-item>
-                <img src="@/assets/images/welcomebg2.png" alt="" />
-            </el-carousel-item>
-        </el-carousel>
-        <div class="left">
-            <div class="logo">
-                <img src="@/assets/images/welcomelogo.png" alt="" />
-            </div>
-        </div>
-        <div class="right">
-            <div class="title">{{projectName}}</div>
-            <div class="title sub-title">欢迎登录</div>
-            <!-- <div class="select_login_type">
-                <div class="type_item type_item_active">
-                    <span>密码登录</span>
-                    <div class="select"></div>
-                </div>
-                <div class="type_item">
-                    <span>短信登录</span>
-                    <div class="select"></div>
-                </div>
-                <div class="type_item">
-                    <span>扫码登录</span>
-                    <div class="select"></div>
-                </div>
-            </div> -->
-            <div class="input_tjm account_ctx">
-                <div>
-                    <input v-model="username" placeholder="请输入用户名" />
-                </div>
-                <div class="tjm_input_icon">
-                    <img src="@/assets/images/user.png" alt="" />
-                </div>
-            </div>
-            <div class="input_tjm pwd_ctx">
-                <div>
-                    <input v-model="password" type="password" placeholder="请输入密码" />
-                </div>
-                <div class="tjm_input_icon">
-                    <img src="@/assets/images/pwd.png" alt="" />
-                </div>
-            </div>
-            <div class="tjm_login_btn" @click="login">登录</div>
-            <!-- <div class="tjm_other_opea">
-                <span>操作手册</span><span>忘记密码</span>
-            </div> -->
-        </div>
+    <el-carousel height="100vh" :pause-on-hover="false">
+        <el-carousel-item>
+            <img src="@/assets/images/welcomebg1.png" alt="" />
+        </el-carousel-item>
+        <el-carousel-item>
+            <img src="@/assets/images/welcomebg2.png" alt="" />
+        </el-carousel-item>
+    </el-carousel>
+
+    <div class="left">
+        <img src="@/assets/images/welcomelogo.png" alt="" />
     </div>
-    <!-- 强制修改密码 -->
-    <el-dialog
-        title="修改密码"
-        v-model="passwordOpen"
-        width="680px"
-        append-to-body
-    >
-        <el-form ref="userRef" :model="form" :rules="rules" label-width="100px">
-            <el-row>
-                <el-col :span="24">
-                    <el-form-item label="用户名" prop="username">
-                        <el-input
-                        v-model="form.username"
-                        placeholder="请输入用户名"
-                        clearable
-                        />
-                    </el-form-item>
-                </el-col>
-                <el-col :span="24">
-                    <el-form-item label="原密码" prop="oldPassword">
-                        <el-input
-                        v-model="form.oldPassword"
-                        type="password"
-                        placeholder="请输入原密码"
-                        clearable
-                        />
-                    </el-form-item>
-                </el-col>
-                <el-col :span="24">
-                    <el-form-item label="新密码" prop="newPassword">
-                        <el-input
-                        v-model="form.newPassword"
-                        type="password"
-                        placeholder="请输入新密码"
-                        clearable
-                        />
-                    </el-form-item>
-                </el-col>
-                <el-col :span="24">
-                    <el-form-item label="确认密码" prop="confirmPassword">
-                        <el-input
-                        v-model="form.confirmPassword"
-                        placeholder="请再次确认密码"
-                        clearable
-                        />
-                    </el-form-item>
-                </el-col>
-            </el-row>
-        </el-form>
-        <template #footer>
-            <div class="dialog-footer">
-                <el-button type="primary" @click="submitForm">确 定</el-button>
-                <el-button @click="cancel">取 消</el-button>
-            </div>
-        </template>
-    </el-dialog>
-    <!-- 强制验证手机号 -->
-    <el-dialog
-        title="手机号验证"
-        v-model="phoneOpen"
-        width="680px"
-        append-to-body
-    >
-        <el-form
-            ref="phoneRef"
-            :model="mobileForm"
-            :rules="mobileRules"
-            label-width="100px"
-        >
+    <div class="right">
+        <div class="title">{{ projectName }}</div>
+        <div class="title sub-title">欢迎登录</div>
+        <el-form>
             <el-row>
                 <el-col :span="24">
-                    <el-form-item label="手机号" prop="mobileNumber">
-                        <el-input
-                        v-model="mobileForm.mobileNumber"
-                        placeholder="请输入手机号"
-                        clearable
-                        />
+                    <el-form-item>
+                        <el-input v-model="username" placeholder="请输入用户名">
+                            <template #prefix>
+                                <img src="@/assets/images/user.png" alt="" />
+                            </template>
+                        </el-input>
                     </el-form-item>
                 </el-col>
                 <el-col :span="24">
-                    <el-form-item label="验证码" prop="verificationCode">
-                        <el-input class="input-with-select" v-model="mobileForm.verificationCode" placeholder="请输入验证码">
-                            <template #append>
-                                <el-button :disabled="countdown > 0" @click="sendVerificationCode">
-                                    {{ countdown > 0 ? countdown + '秒后重新获取' : '获取验证码' }}
-                                </el-button>
+                    <el-form-item>
+                        <el-input v-model="password" type="password" show-password placeholder="请输入密码">
+                            <template #prefix>
+                                <img src="@/assets/images/pwd.png" alt="" />
                             </template>
                         </el-input>
                     </el-form-item>
                 </el-col>
+                <el-col :span="24">
+                    <el-button class="login-btn" :loading="isSaving" @click="login">登录</el-button>
+                </el-col>
             </el-row>
         </el-form>
-        <template #footer>
-            <div class="dialog-footer">
-                <el-button type="primary" @click="submitPhoneForm">确 定</el-button>
-                <el-button @click="phoneCancel">取 消</el-button>
-            </div>
-        </template>
-    </el-dialog>
+    </div>
+
+    <!-- 强制修改密码 -->
+    <update-pwd ref="updatePwd"></update-pwd>
 </template>
 
 <script setup>
-import { getConfig } from '@/config/config'
-import { useUserStore } from '@/store/user.js'
-import { passwordChange, sendSmsCode, userUnlock } from '@/api/login'
-import CryptoJS from 'crypto-js'
-// const route = useRoute()
-const router = useRouter()
-const passwordOpen = ref(false)
-const phoneOpen = ref(false)
-const username = ref('')
-const password = ref('')
-const { proxy } = getCurrentInstance()
-const countdown = ref(0) // 倒计时秒数
-const projectName = ref(getConfig('projectName'))
+import { getConfig } from "@/config/config";
+import { useUserStore } from "@/store/user";
+import { passwordChange, sendSmsCode, userUnlock } from "@/api/login";
+import CryptoJS from "crypto-js";
+import UpdatePwd from "./updatePwd.vue";
 
-const form = ref({
-    username: null,
-    oldPassword: null,
-    newPassword: null,
-    confirmPassword: null
-})
-const mobileForm = ref({
-    mobileNumber: null,
-    verificationCode: null
-})
-const mobileRules = ref({
-    mobileNumber: [
-        { required: true, message: '手机号不能为空', trigger: 'blur' }
-    ],
-    verificationCode: [
-        { required: true, message: '验证码不能为空', trigger: 'blur' }
-    ]
-})
-const rules = ref({
-    username: [{ required: true, message: '用户名不能为空', trigger: 'blur' }],
-    oldPassword: [{ required: true, message: '旧密码不能为空', trigger: 'blur' }],
-    newPassword: [
-        { required: true, message: '新密码不能为空', trigger: 'blur' },
-        {
-            pattern:
-                /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
-            message: '新密码必须至少8位,且必须包含大小写字母、数字和特殊符号',
-            trigger: 'blur'
-        }
-    ],
-    confirmPassword: [
-        { required: true, message: '请在此输入新密码', trigger: 'blur' },
-        {
-            validator: (rule, value, callback) => {
-                if (value !== form.value.newPassword) {
-                    console.log(value, form.value.newPassword, 'Lingci')
-                    callback(new Error('两次输入的密码不一致'))
-                } else {
-                    callback()
-                }
-            },
-            trigger: 'blur'
-        }
-    ]
-})
+const router = useRouter();
+const projectName = ref(getConfig("projectName"));
+const username = ref("");
+const password = ref("");
 
-const login = () => {
-    useUserStore()
-        .login({
-            username: username.value,
-            password: password.value
-        })
-        .then(() => {
-            router.push('/')
-        })
-        .catch(code => {
-            console.log('错误进来了', code)
-            if (code === 204) {
-                console.log('强制修改密码')
-                password.value = ''
-                passwordOpen.value = true
-            } else if (code === 203) {
-                password.value = ''
-                phoneOpen.value = true
-            }
-        })
-}
+const updatePwd = ref();
+const isSaving = ref(false);
 
-function submitForm() {
-    proxy.$refs['userRef'].validate(valid => {
-        if (valid) {
-            passwordChange({
-                userName: form.value.username,
-                oldPassword: CryptoJS.MD5(form.value.oldPassword).toString(),
-                newPassword: CryptoJS.MD5(form.value.newPassword).toString(),
-                enterPassword: CryptoJS.MD5(form.value.confirmPassword).toString()
-            }).then(res => {
-                if (res.success) {
-                    ElMessage({
-                        message: '修改成功,请重新登录!',
-                        type: 'success'
-                    })
-                    passwordOpen.value = false
-                }
-            })
-        } else {
-            console.log('检验不通过')
-        }
+const login = () => {
+    isSaving.value = true;
+    useUserStore().login({
+        username: username.value,
+        password: password.value
+    }).then(() => {
+        isSaving.value = false;
+        router.push("/");
+    }).catch(code => {
+        isSaving.value = false;
+        if (code === 204) {
+            password.value = "";
+            updatePwd.value.open();
+        } 
     })
 }
 
-function cancel() {
-    passwordOpen.value = false
-    form.value = {
-        username: null,
-        oldPassword: null,
-        newPassword: null,
-        confirmPassword: null
-    }
-}
 
-function sendVerificationCode() {
-    // 这里实现发送验证码的逻辑
-    if (!mobileForm.value.mobileNumber) return
-    sendSmsCode({ mobile: mobileForm.value.mobileNumber }).then(res => {
-        if (res.success) {
-            ElMessage({
-                message: '验证码发生成功!',
-                type: 'success'
-            })
-            // 发送成功后开始倒计时
-            countdown.value = 60
-            let interval = setInterval(() => {
-                countdown.value--
-                if (countdown.value <= 0) {
-                    clearInterval(interval)
-                }
-            }, 1000)
-        }
-    })
-}
+</script>
 
-function submitPhoneForm() {
-    proxy.$refs['phoneRef'].validate(valid => {
-        if (valid) {
-            userUnlock({
-                mobile: mobileForm.value.mobileNumber,
-                code: mobileForm.value.verificationCode
-            }).then(res => {
-                if (res.success) {
-                    ElMessage({
-                        message: '校验成功,请重新登录',
-                        type: 'success'
-                    })
-                    phoneOpen.value = false
-                }
-            })
-        } else {
-            console.log('校验不通过')
-        }
-    })
-}
+<style lang="scss" scoped>
+.el-carousel {
+  position: fixed; //视频定位方式设为固定
+  right: 0;
+  bottom: 0; //视频位置
+  min-width: 100%;
+  min-height: 100%; //不会因视频尺寸造成页面需要滚动
+  width: auto;
+  height: auto; //尺寸保持原视频大小
+  z-index: -100; //z轴定位,小于0即可
 
-function phoneCancel() {
-    phoneOpen.value = false
-    mobileForm.value = {
-        mobileNumber: null,
-        verificationCode: null
-    }
+  img {
+    width: 100%;
+    height: 100%;
+  }
 }
-</script>
 
-<style lang='scss' scoped>
-.tjm_login {
-  margin: 0;
-  padding: 0;
-  display: flex;
-  width: 100%;
+.left {
+  position: fixed; //视频定位方式设为固定
   height: 100%;
+  min-height: 100%; //不会因视频尺寸造成页面需要滚动
+
+  img {
+    width: 316px;
+    height: 72px;
+    margin: 46px 0 0 80px;
+  }
+}
+
+.right {
+  position: fixed; //视频定位方式设为固定
+  width: 500px;
+  right: 0;
+  min-height: 100%; //不会因视频尺寸造成页面需要滚动
+  background: rgba(255, 255, 255, 0.68);
+  border-left: 1px solid #ffffff;
+  box-shadow: 2px 0px 0px 0px rgba(255, 255, 255, 1) inset;
   display: flex;
-  justify-content: space-between;
-  .el-carousel {
-    position: fixed; //视频定位方式设为固定
-    right: 0;
-    bottom: 0; //视频位置
-    min-width: 100%;
-    min-height: 100%; //不会因视频尺寸造成页面需要滚动
-    width: auto;
-    height: auto; //尺寸保持原视频大小
-    z-index: -100; //z轴定位,小于0即可
+  flex-direction: column;
+  align-items: center;
 
-    img {
-      width: 100%;
-      height: 100%;
-    }
+  .title {
+    width: 81.6%;
+    font-family: PingFang SC;
+    font-size: 36px;
+    font-weight: 600;
+    line-height: 28px;
+    margin: 100px 0 0;
   }
 
-  .left {
-    position: fixed; //视频定位方式设为固定
-    height: 100%;
-    min-height: 100%; //不会因视频尺寸造成页面需要滚动
-    .logo {
-      img {
-        width: 316px;
-        height: 72px;
-        margin: 46px 0 0 80px;
-        // border:1px solid red;
-      }
-    }
+  .sub-title {
+    font-size: 28px;
+    font-weight: 500;
   }
-  .right {
-    position: fixed; //视频定位方式设为固定
-    width: 500px;
-    right: 0;
-    min-height: 100%; //不会因视频尺寸造成页面需要滚动
-    background: rgba(255, 255, 255, 0.68);
-    border-left: 1px solid #ffffff;
-    box-shadow: 2px 0px 0px 0px rgba(255, 255, 255, 1) inset;
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    .title {
-      width: 81.6%;
-      font-family: PingFang SC;
-      font-size: 36px;
-      font-weight: 600;
-      line-height: 28px;
-      margin: 100px 0 0;
-    }
 
-    .sub-title {
-      font-size: 28px;
-      font-weight: 500;
-    }
-    .select_login_type {
-      width: 81.6%;
-      height: 38px;
-      margin: 86px 0 0 0px;
-      display: flex;
-      .type_item {
-        font-family: PingFang SC;
-        font-size: 16px;
-        font-weight: 500;
-        text-align: left;
-        line-height: 28px;
-        color: rgba(102, 102, 102, 1);
-        margin-right: 40px;
-        cursor: pointer;
-      }
-      .type_item_active {
-        color: rgba(0, 0, 0, 1);
-        font-family: PingFang SC;
+  .el-form {
+    width: 81.6%;
+    margin-top: 40px;
+
+    .el-form-item {
+      margin-bottom: 0;
+      margin-top: 28px;
+
+      .el-input {
+        --el-component-size: 52px;
+        --el-input-text-color: #1d2129;
         font-size: 16px;
-        font-weight: 600;
-        line-height: 28px;
-        text-align: left;
-        display: flex;
-        flex-direction: column;
-        justify-content: space-between;
-        .select {
-          width: 65px;
-          height: 4px;
-          gap: 0px;
-          border-radius: 8px 0px 0px 0px;
-          opacity: 0px;
 
-          background: linear-gradient(270.6deg, #165dff 2.71%, #45b1ff 99.81%);
+        :deep(.el-input__wrapper) {
+          box-shadow: 0 0;
+          border-radius: calc(2 * var(--el-border-radius-base));
+
+          .el-input__prefix {
+            padding: 0 calc(25px / 2);
+
+            img {
+              width: 24px;
+              height: 24px;
+            }
+          }
+
+          .el-input__inner {
+            padding-left: 11px;
+            font-family: PingFang SC;
+            font-weight: 600;
+          }
         }
       }
     }
-    .input_tjm {
-      width: 81.6%;
-      position: relative;
-      //
-      .tjm_input_icon {
-        position: absolute;
-        top: 40px;
-        left: 24px;
-        width: 24px;
-        height: 24px;
-        img {
-          width: 24px;
-          height: 24px;
-        }
-      }
-      input {
-        width: 100%;
-        height: 52px;
-        margin-top: 28px;
-        background: rgba(255, 255, 255, 1);
-        border-radius: 8px;
-        border: none;
-        user-select: none;
-        outline: none;
-        font-family: PingFang SC;
-        font-size: 16px;
-        font-weight: 600;
-        line-height: 52px;
-        text-align: left;
-        color: rgba(29, 33, 41, 1);
-        text-indent: 68px;
-      }
-    }
-    .account_ctx {
-      margin-top: 40px;
-    }
-    .tjm_login_btn {
-      cursor: pointer;
-      width: 81.6%;
+
+    .login-btn {
+      width: 100%;
       height: 56px;
+      margin-top: 72px;
+      padding: 0;
       background: linear-gradient(270.6deg, #165dff 2.71%, #45b1ff 99.81%);
-      margin: 72px 0 0 0px;
-      color: rgba(255, 255, 255, 1);
-      font-family: PingFang SC;
-      font-size: 20px;
-      font-weight: 600;
-      line-height: 56px;
-      text-align: center;
+      border: none;
       border-radius: 8px;
-    }
-    .tjm_other_opea {
-      width: 81.6%;
-      height: 22px;
-      margin: 28px 0 0 0px;
-      gap: 0px;
-      opacity: 0px;
-      display: flex;
-      justify-content: space-between;
-      span {
-        cursor: pointer;
-        font-size: 16px;
-        font-weight: 400;
-        text-align: center;
-        color: rgba(29, 33, 41, 0.65);
-      }
+      font: 20px PingFang SC;
+      font-weight: 600;
+      color: #fff;
     }
   }
 }

+ 275 - 0
src/views/login/updatePwd.vue

@@ -0,0 +1,275 @@
+<template>
+    <el-dialog v-model="visible" title="修改密码" width="680px">
+        <el-form ref="userRef" :model="form" :rules="rules" label-width="100px">
+            <el-row>
+                <el-col :span="24">
+                    <el-form-item label="用户名" prop="username">
+                        <el-input v-model="form.username" placeholder="请输入用户名" />
+                    </el-form-item>
+                </el-col>
+                <el-col :span="24">
+                    <el-form-item label="原密码" prop="oldPassword">
+                        <el-input v-model="form.oldPassword" type="password" show-password placeholder="请输入原密码" />
+                    </el-form-item>
+                </el-col>
+                <el-col :span="24">
+                    <el-form-item label="新密码" prop="newPassword">
+                        <el-input v-model="form.newPassword" type="password" show-password placeholder="请输入新密码" />
+                    </el-form-item>
+                </el-col>
+                <el-col :span="24">
+                    <el-form-item label="确认密码" prop="confirmPassword">
+                        <el-input v-model="form.confirmPassword" type="password" show-password placeholder="请再次确认密码" />
+                    </el-form-item>
+                </el-col>
+            </el-row>
+        </el-form>
+
+        <template #footer>
+            <el-button type="primary" @click="submitForm">确 定</el-button>
+            <el-button @click="cancel">取 消</el-button>
+        </template>
+    </el-dialog>
+</template>
+
+<script setup>
+import CryptoJS from "crypto-js";
+import { useUserStore } from "@/store/user";
+import { passwordChange } from "@/api/login";
+
+const userRef = ref();
+const visible = ref(false);
+const form = ref({
+    username: null,
+    oldPassword: null,
+    newPassword: null,
+    confirmPassword: null
+})
+
+const rules = reactive({
+    username: [{ required: true, trigger: "blur", message: "用户名不能为空" }],
+    oldPassword: [{ required: true, trigger: "blur", message: "旧密码不能为空" }],
+    newPassword: [
+        { required: true, trigger: "blur", message: "新密码不能为空" },
+        {
+            pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
+            trigger: "blur",
+            message: "新密码必须至少8位,且必须包含大小写字母、数字和特殊符号"
+        }
+    ],
+    confirmPassword: [
+        { required: true, trigger: "blur", message: "请在此输入新密码" },
+        {   trigger: "blur", validator: (rule, value, callback) => {
+                if (value !== form.value.newPassword) return callback(new Error("两次输入的密码不一致"))
+                callback()
+            }
+        }
+    ]
+})
+
+const open = () => {
+    visible.value = true;
+}
+
+function submitForm() {
+    userRef.value.validate(valid => {
+        if (valid) {
+            passwordChange({
+                userName: form.value.username,
+                oldPassword: CryptoJS.MD5(form.value.oldPassword).toString(),
+                newPassword: CryptoJS.MD5(form.value.newPassword).toString(),
+                enterPassword: CryptoJS.MD5(form.value.confirmPassword).toString()
+            }).then(res => {
+                if (res.success) {
+                    ElMessage.success("修改成功,请重新登录!");
+                    visible.value = false;
+                }
+            });
+        } else {
+            return false;
+        }
+    })
+}
+
+function cancel() {
+    visible.value = false;
+    form.value = {
+        username: null,
+        oldPassword: null,
+        newPassword: null,
+        confirmPassword: null
+    }
+}
+
+defineExpose({
+    open
+})
+</script>
+
+<style lang='scss' scoped>
+.tjm_login {
+  margin: 0;
+  padding: 0;
+  display: flex;
+  width: 100%;
+  height: 100%;
+  display: flex;
+  justify-content: space-between;
+  .el-carousel {
+    position: fixed; //视频定位方式设为固定
+    right: 0;
+    bottom: 0; //视频位置
+    min-width: 100%;
+    min-height: 100%; //不会因视频尺寸造成页面需要滚动
+    width: auto;
+    height: auto; //尺寸保持原视频大小
+    z-index: -100; //z轴定位,小于0即可
+
+    img {
+      width: 100%;
+      height: 100%;
+    }
+  }
+
+  .left {
+    position: fixed; //视频定位方式设为固定
+    height: 100%;
+    min-height: 100%; //不会因视频尺寸造成页面需要滚动
+    .logo {
+      img {
+        width: 316px;
+        height: 72px;
+        margin: 46px 0 0 80px;
+        // border:1px solid red;
+      }
+    }
+  }
+  .right {
+    position: fixed; //视频定位方式设为固定
+    width: 500px;
+    right: 0;
+    min-height: 100%; //不会因视频尺寸造成页面需要滚动
+    background: rgba(255, 255, 255, 0.68);
+    border-left: 1px solid #ffffff;
+    box-shadow: 2px 0px 0px 0px rgba(255, 255, 255, 1) inset;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    .title {
+      width: 81.6%;
+      font-family: PingFang SC;
+      font-size: 36px;
+      font-weight: 600;
+      line-height: 28px;
+      margin: 100px 0 0;
+    }
+
+    .sub-title {
+      font-size: 28px;
+      font-weight: 500;
+    }
+    .select_login_type {
+      width: 81.6%;
+      height: 38px;
+      margin: 86px 0 0 0px;
+      display: flex;
+      .type_item {
+        font-family: PingFang SC;
+        font-size: 16px;
+        font-weight: 500;
+        text-align: left;
+        line-height: 28px;
+        color: rgba(102, 102, 102, 1);
+        margin-right: 40px;
+        cursor: pointer;
+      }
+      .type_item_active {
+        color: rgba(0, 0, 0, 1);
+        font-family: PingFang SC;
+        font-size: 16px;
+        font-weight: 600;
+        line-height: 28px;
+        text-align: left;
+        display: flex;
+        flex-direction: column;
+        justify-content: space-between;
+        .select {
+          width: 65px;
+          height: 4px;
+          gap: 0px;
+          border-radius: 8px 0px 0px 0px;
+          opacity: 0px;
+
+          background: linear-gradient(270.6deg, #165dff 2.71%, #45b1ff 99.81%);
+        }
+      }
+    }
+    .input_tjm {
+      width: 81.6%;
+      position: relative;
+      //
+      .tjm_input_icon {
+        position: absolute;
+        top: 40px;
+        left: 24px;
+        width: 24px;
+        height: 24px;
+        img {
+          width: 24px;
+          height: 24px;
+        }
+      }
+      input {
+        width: 100%;
+        height: 52px;
+        margin-top: 28px;
+        background: rgba(255, 255, 255, 1);
+        border-radius: 8px;
+        border: none;
+        user-select: none;
+        outline: none;
+        font-family: PingFang SC;
+        font-size: 16px;
+        font-weight: 600;
+        line-height: 52px;
+        text-align: left;
+        color: rgba(29, 33, 41, 1);
+        text-indent: 68px;
+      }
+    }
+    .account_ctx {
+      margin-top: 40px;
+    }
+    .tjm_login_btn {
+      cursor: pointer;
+      width: 81.6%;
+      height: 56px;
+      background: linear-gradient(270.6deg, #165dff 2.71%, #45b1ff 99.81%);
+      margin: 72px 0 0 0px;
+      color: rgba(255, 255, 255, 1);
+      font-family: PingFang SC;
+      font-size: 20px;
+      font-weight: 600;
+      line-height: 56px;
+      text-align: center;
+      border-radius: 8px;
+    }
+    .tjm_other_opea {
+      width: 81.6%;
+      height: 22px;
+      margin: 28px 0 0 0px;
+      gap: 0px;
+      opacity: 0px;
+      display: flex;
+      justify-content: space-between;
+      span {
+        cursor: pointer;
+        font-size: 16px;
+        font-weight: 400;
+        text-align: center;
+        color: rgba(29, 33, 41, 0.65);
+      }
+    }
+  }
+}
+</style>

+ 109 - 0
src/views/system/log/index.vue

@@ -0,0 +1,109 @@
+<template>
+    <el-card class="tjm_card_style_custom">
+        <div class="tjm_card_title">条件检索</div>
+        <div class="tjm_card_select">
+            <el-form class="tjm_card_select_left" :model="params" inline label-width="80px" label-position="left">
+                <el-form-item label="操作人">
+                    <el-input v-model="params.userName" clearable placeholder="请输入操作人"></el-input>
+                </el-form-item>
+                <el-form-item label="操作名称">
+                    <el-input v-model="params.operateName" clearable placeholder="请输入模块"></el-input>
+                </el-form-item>
+                <el-form-item label="业务类型">
+                    <el-select v-model="params.operateType" clearable placeholder="请选择业务类型">
+                        <el-option v-for="(label, key) in typeDic" :key="key" :label="label" :value="key"></el-option>
+                    </el-select>
+                </el-form-item>
+                <el-form-item label="操作日期">
+                    <el-date-picker v-model="createTime" type="daterange" value-format="YYYY-MM-DD" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
+                </el-form-item>
+
+                <el-form-item>
+                    <el-button type="primary" icon="search" @click="reloadTable">搜索</el-button>
+                    <el-button icon="refresh-right" @click="reset">重置</el-button>
+                </el-form-item>
+            </el-form>
+        </div>
+        <el-divider></el-divider>
+
+        <div class="tjm_card_table">
+            <el-table v-loading="loading" row-key="id" header-cell-class-name="tjm_card_table_header" height="400" :data="tableData" border>
+                <el-table-column type="index" label="序号" width="55"></el-table-column>
+                <el-table-column label="操作人" prop="userName"></el-table-column>
+                <el-table-column label="登录名" prop="loginName"></el-table-column>
+                <el-table-column label="操作时间" prop="createTime" show-overflow-tooltip></el-table-column>
+                <el-table-column label="业务类型" show-overflow-tooltip>
+                    <template #default="scope">{{ formatType(scope.row.operateType) }}</template>
+                </el-table-column>
+                <el-table-column label="操作名称" prop="operateName" show-overflow-tooltip></el-table-column>
+                <el-table-column label="IP" prop="ipHost" show-overflow-tooltip></el-table-column>
+            </el-table>
+        </div>
+        <div class="tjm_card_pagination">
+            <yh-pagination v-model:pageNo="params.page" v-model:pageSize="params.size" :total="total" @paginationChange="reloadTable"></yh-pagination>
+        </div>
+    </el-card>
+</template>
+
+<script>
+import API from "@/api/system/log";
+import { typeDic } from "./main";
+
+import yhPagination from "@/components/Pagination/index.vue";
+
+export default {
+    components: {
+        yhPagination
+    },
+
+    data() {
+        return {
+            typeDic,
+            
+            loading: false,
+            createTime: [],
+            params: {
+                page: 1,
+                size: 10
+            },
+
+            total: 0,
+            tableData: []
+        }
+    },
+
+    mounted() {
+        this.reloadTable();
+    },
+
+    methods: {
+        formatType(value) {
+            return typeDic[value] || value;
+        },
+
+        reloadTable() {
+            this.params.beginCreateTime = this.createTime && this.createTime.length && this.createTime[0] + " 00:00:00" || null;
+            this.params.endCreateTime = this.createTime && this.createTime.length && this.createTime[1] + " 23:59:59" || null;
+
+            this.loading = true;
+            API.get(this.params).then(res => {
+                this.loading = false;
+                if (res.code === 200) {
+                    this.tableData = res.data.records;
+                    this.total = res.data.total;
+                } else ElMessage.error(res.msg);
+            }).catch(() => this.loading = false);
+        },
+
+        reset() {
+            this.createTime = [];
+            this.params = {
+                page: 1,
+                size: 10
+            }
+                
+            this.reloadTable();
+        },
+    }
+}
+</script>

+ 13 - 0
src/views/system/log/main.js

@@ -0,0 +1,13 @@
+export const typeDic = {
+    login_system: "登录系统",
+    logout_system: "退出系统",
+    update_password: "修改密码",
+    system_userInfo: "用户信息",
+
+    policy_share: "政策分享",
+    policy_strive: "政策争取",
+    policy_case: "案例分享",
+    policy_message: "留言",
+    policy_template: "模板管理",
+    policy_condition: "应填报日期管理"
+}

+ 41 - 48
src/views/system/userInfo.vue

@@ -101,15 +101,24 @@
 
         <el-dialog v-model="isPwdDialogVisible" title="修改密码" width="500">
             <el-form ref="pwdFormRef" :model="pwdForm" :rules="pwdRules" label-width="120px">
-                <el-form-item label="旧密码" prop="oldPassword">
-                    <el-input v-model="pwdForm.oldPassword" type="password" autocomplete="off"></el-input>
-                </el-form-item>
-                <el-form-item label="新密码" prop="newPassword">
-                    <el-input v-model="pwdForm.newPassword" type="password" autocomplete="off"></el-input>
-                </el-form-item>
-                <el-form-item label="确认密码" prop="enterPassword">
-                    <el-input v-model="pwdForm.enterPassword" type="password" autocomplete="off"></el-input>
-                </el-form-item>
+                <el-row>
+                    <el-col :span="24">
+                        <el-form-item label="原密码" prop="oldPassword">
+                            <el-input v-model="pwdForm.oldPassword" type="password" show-password placeholder="请输入原密码" />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="24">
+                        <el-form-item label="新密码" prop="newPassword">
+                            <el-input v-model="pwdForm.newPassword" type="password" show-password placeholder="请输入新密码" />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="24">
+                        <el-form-item label="确认密码" prop="enterPassword">
+                            <el-input v-model="pwdForm.enterPassword" type="password" show-password placeholder="请再次确认密码" />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+
             </el-form>
             <template #footer>
                 <span class="dialog-footer">
@@ -122,11 +131,12 @@
 </template>
 
 <script setup>
-import { getUserInfo, upChangePassword, updateUserInfo } from '@/api/system/person'
+import { getUserInfo, upChangePassword, updateUserInfo } from "@/api/system/person";
+import API from "@/api/system/log";
 import Folder from "@/api/folder.js";
-import { Encrypt } from '@/utils/aes'
-import { useUserStore } from '@/store/user.js'
-import router from '@/router'
+import { Encrypt } from "@/utils/aes";
+import { useUserStore } from "@/store/user";
+import router from "@/router";
 
 const pwdFormRef = ref(null)
 const isPwdDialogVisible = ref(false)
@@ -151,25 +161,21 @@ const form = ref({
 })
 
 const pwdRules = ref({
-    oldPassword: [
-        { required: true, message: '请输入旧密码', trigger: 'blur' }
-    ],
+    oldPassword: [{ required: true, trigger: "blur", message: "旧密码不能为空" }],
     newPassword: [
-        { required: true, message: '请输入新密码', trigger: 'blur' },
-        { min: 6, message: '密码长度不能小于6位', trigger: 'blur' }
+        { required: true, trigger: "blur", message: "新密码不能为空" },
+        {
+            pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
+            trigger: "blur",
+            message: "新密码必须至少8位,且必须包含大小写字母、数字和特殊符号"
+        }
     ],
     enterPassword: [
-        { required: true, message: '请再次输入新密码', trigger: 'blur' },
-        { min: 6, message: '密码长度不能小于6位', trigger: 'blur' },
-        // 添加一个自定义校验规则来确保新密码和确认密码一致
-        {
-            validator: (rule, value, callback) => {
-                if (value !== pwdForm.value.newPassword) {
-                    callback(new Error('两次输入的密码不一致'))
-                } else {
-                    callback()
-                }
-            }, trigger: 'blur'
+        { required: true, trigger: "blur", message: "请在此输入新密码" },
+        {   trigger: "blur", validator: (rule, value, callback) => {
+                if (value !== pwdForm.value.newPassword) return callback(new Error("两次输入的密码不一致"))
+                callback()
+            }
         }
     ]
 })
@@ -206,21 +212,12 @@ function changeInfo() {
                 type: 'warning'
             })
         } else {
-            let { avatar, email, mobile, name } = form.value
-            updateUserInfo({
-                avatar,
-                email,
-                mobile,
-                name
-            }
-            ).then((res) => {
+            updateUserInfo(form.value).then((res) => {
                 if (res.code == 200) {
-                    isEdit.value = false
-                    getList()
-                    ElMessage({
-                        message: '修改成功',
-                        type: 'success'
-                    })
+                    ElMessage.success("修改成功");
+                    isEdit.value = false;
+                    API.add("修改", "system_userInfo");
+                    getList();
                 }
             })
         }
@@ -242,18 +239,14 @@ function changePassword() {
                 enterPassword: Encrypt(pwdForm.value.enterPassword)
             }).then((res) => {
                 if (res.code == 200) {
-                    console.log('密码修改成功', pwdForm.value)
                     cancelPassword()
                     ElMessage.success('密码修改成功')
-                    useUserStore().logOut().then(() => {
-                        router.push('/login')
-                    })
+                    API.add("修改密码", "update_password").then(() => useUserStore().logOut().then(() => router.push("/login")));
                 } else {
                     ElMessage.error(res.msg)
                 }
             })
         } else {
-            ElMessage.error('表单数据有误,请按提示修改后再提交')
             return false
         }
     })

+ 0 - 12
src/views/test/index1.vue

@@ -1,12 +0,0 @@
-<script setup>
-
-</script>
-
-<template>
-    <div>
-        测试1
-    </div>
-</template>
-
-<style lang='scss' scoped>
-</style>

+ 0 - 12
src/views/test/index2.vue

@@ -1,12 +0,0 @@
-<script setup>
-
-</script>
-
-<template>
-    <div>
-        测试2
-    </div>
-</template>
-
-<style lang='scss' scoped>
-</style>

+ 0 - 12
src/views/test/index3.vue

@@ -1,12 +0,0 @@
-<script setup>
-
-</script>
-
-<template>
-    <div>
-        测试3
-    </div>
-</template>
-
-<style lang='scss' scoped>
-</style>

+ 0 - 12
src/views/test/index4.vue

@@ -1,12 +0,0 @@
-<script setup>
-
-</script>
-
-<template>
-    <div>  
-        index4
-    </div>
-</template>
-
-<style lang='scss' scoped>
-</style>