Merge remote-tracking branch 'origin/develop' into feature/device
# Conflicts: # .env.development # .eslintrc.js # components.d.ts # config/vite.config.dev.ts # index.html # package.json # pnpm-lock.yaml # src/api/authority.ts # src/api/dept.ts # src/api/interceptor.ts # src/api/message.ts # src/api/role.ts # src/api/user.ts # src/assets/world.json # src/components/breadcrumb/index.vue # src/components/footer/index.vue # src/components/menu/index.vue # src/components/message-box/index.vue # src/components/message-box/list.vue # src/components/navbar/index.vue # src/components/tab-bar/readme.md # src/components/tab-bar/tab-item.vue # src/config/settings.json # src/directive/permission/index.ts # src/hooks/permission.ts # src/locale/en-US.ts # src/locale/zh-CN.ts # src/mock/index.ts # src/router/guard/permission.ts # src/router/guard/userLoginInfo.ts # src/router/routes/modules/dashboard.ts # src/router/routes/modules/system.ts # src/router/routes/modules/user.ts # src/store/index.ts # src/store/modules/auth/index.ts # src/store/modules/auth/type.ts # src/store/modules/user/index.ts # src/store/modules/user/types.ts # src/utils/excel.ts # src/views/dashboard/workplace/components/banner.vue # src/views/dashboard/workplace/components/data-panel.vue # src/views/dashboard/workplace/index.vue # src/views/dashboard/workplace/locale/en-US.ts # src/views/dashboard/workplace/locale/zh-CN.ts # src/views/exception/403/index.vue # src/views/exception/404/index.vue # src/views/exception/500/index.vue # src/views/login/components/banner.vue # src/views/login/components/login-form.vue # src/views/login/index.vue # src/views/login/locale/en-US.ts # src/views/login/locale/zh-CN.ts # src/views/system/authority/components/auth-edit.vue # src/views/system/authority/components/auth-table.vue # src/views/system/authority/index.vue # src/views/system/authority/locale/en-US.ts # src/views/system/authority/locale/zh-CN.ts # src/views/system/dept/components/dept-edit.vue # src/views/system/dept/index.vue # src/views/system/dept/locale/en-US.ts # src/views/system/dept/locale/zh-CN.ts # src/views/system/permission/index.vue # src/views/system/role/components/role-edit.vue # src/views/system/role/index.vue # src/views/system/role/locale/en-US.ts # src/views/system/role/locale/zh-CN.ts # src/views/system/user/components/user-edit.vue # src/views/system/user/index.vue # src/views/system/user/locale/en-US.ts # src/views/system/user/locale/zh-CN.ts # src/views/user/setting/components/basic-information.vue # src/views/user/setting/components/password-reset.vue # src/views/user/setting/components/user-panel.vue # src/views/user/setting/index.vue # src/views/user/setting/locale/en-US.ts # src/views/user/setting/locale/zh-CN.ts
This commit is contained in:
commit
309dffa60b
@ -1,3 +1,2 @@
|
||||
VITE_API_URL= ''
|
||||
|
||||
|
||||
# VITE_API_BASE_URL= 'http://localhost:8080'
|
||||
VITE_API_BASE_URL= '/'
|
@ -36,7 +36,7 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'prettier/prettier': 0,
|
||||
'prettier/prettier': 1,
|
||||
// Vue: Recommended rules to be closed or modify
|
||||
'vue/require-default-prop': 0,
|
||||
'vue/singleline-html-element-content-newline': 0,
|
||||
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -3,8 +3,10 @@ node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
.idea
|
||||
.husky
|
||||
*.log
|
||||
*-lock.json
|
||||
yarn.lock
|
10
.idea/.gitignore
vendored
Normal file
10
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
.idea/
|
||||
yarn.lock
|
27
index.html
27
index.html
@ -1,16 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="./src/assets/objectNetwork.png" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>物联网网关系统</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link
|
||||
rel="shortcut icon"
|
||||
type="image/x-icon"
|
||||
href="https://unpkg.byted-static.com/latest/byted/arco-config/assets/favicon.ico"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>物联网网关系统</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
@ -2,11 +2,11 @@ import axios from 'axios';
|
||||
|
||||
export interface AuthCreateRecord {
|
||||
name: string;
|
||||
// dataScope: string;
|
||||
// permissionIds: (number | undefined)[];
|
||||
// dataScope: string;
|
||||
// permissionIds: (number | undefined)[];
|
||||
remark: string;
|
||||
enabled: boolean;
|
||||
// authorities: (number | undefined)[];
|
||||
// authorities: (number | undefined)[];
|
||||
}
|
||||
|
||||
// 基础信息
|
||||
@ -21,35 +21,35 @@ export interface AuthRecord extends AuthCreateRecord {
|
||||
// 查询所有的权限列表
|
||||
export function queryAuthList(data: any) {
|
||||
return axios({
|
||||
url: '/api/rest/authority', // 路径
|
||||
url: '/api/rest/auth', // 路径
|
||||
method: 'get',
|
||||
params: data, // 参数
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 切换启用状态
|
||||
export function enabled(id: string) {
|
||||
return axios.patch(`/api/rest/authority/toggle/${id}`);
|
||||
return axios.patch(`/api/rest/auth/toggle/${id}`);
|
||||
}
|
||||
|
||||
// 删除
|
||||
export function remove(id: string) {
|
||||
return axios.delete(`/api/rest/authority/${id}`);
|
||||
return axios.delete(`/api/rest/auth/${id}`);
|
||||
}
|
||||
|
||||
// 添加
|
||||
export function create(data: AuthCreateRecord) {
|
||||
return axios.post(`/api/rest/authority`, data);
|
||||
return axios.post(`/api/rest/auth`, data);
|
||||
}
|
||||
|
||||
// 更新
|
||||
export function update(data: AuthRecord) {
|
||||
return axios.patch(`/api/rest/authority/${data.id}`, data);
|
||||
return axios.patch(`/api/rest/auth/${data.id}`, data);
|
||||
}
|
||||
|
||||
// 获取详情
|
||||
export function getDetail(id: string) {
|
||||
return axios.get<AuthRecord>(`/api/rest/authority/${id}`);
|
||||
return axios.get<AuthRecord>(`/api/rest/auth/${id}`);
|
||||
}
|
||||
|
||||
// export function queryRoles(params?: ListParams<Partial<RoleRecord>>) {
|
||||
|
@ -29,9 +29,8 @@ export interface PasswordReSetModel {
|
||||
|
||||
// 添加用户数据
|
||||
export interface CreateRecord {
|
||||
value: any;
|
||||
code: any;
|
||||
|
||||
value: any;
|
||||
code: any;
|
||||
username: string;
|
||||
nickName: string;
|
||||
password: string;
|
||||
@ -40,7 +39,7 @@ code: any;
|
||||
enabled: string;
|
||||
address: string;
|
||||
deptId: DeptRecord | undefined;
|
||||
roleId: string| RoleRecord | undefined;
|
||||
roleId: string | RoleRecord | undefined;
|
||||
permissionIds: (number | undefined)[];
|
||||
authorities: string[];
|
||||
}
|
||||
@ -58,13 +57,13 @@ export interface UserRecord extends CreateRecord {
|
||||
value: any;
|
||||
id: string;
|
||||
avatar: string;
|
||||
createAt: string
|
||||
createAt: string;
|
||||
}
|
||||
|
||||
export interface UserParams extends Partial<UserRecord> {
|
||||
page: number;
|
||||
size: number;
|
||||
current: number
|
||||
current: number;
|
||||
}
|
||||
|
||||
export interface Pageable {
|
||||
@ -128,11 +127,10 @@ export function queryUserList(params: any) {
|
||||
}
|
||||
|
||||
// 根据id查询用户信息
|
||||
export function userDetail(id: string){
|
||||
return axios.get(`/api/rest/user/${id}`)
|
||||
export function userDetail(id: string) {
|
||||
return axios.get(`/api/rest/user/${id}`);
|
||||
}
|
||||
|
||||
|
||||
// 是否启用
|
||||
export function enabled(id: string) {
|
||||
return axios.patch(`/api/rest/user/${id}/toggle`);
|
||||
@ -158,7 +156,7 @@ export function getUserInfo() {
|
||||
}
|
||||
|
||||
// 部门的审核员
|
||||
export function deptAudit(id: string,roleId:string){
|
||||
export function deptAudit(id: string, roleId: string) {
|
||||
return axios({
|
||||
url: `/api/rest/user/dept/${id}?roleId=${roleId}`, // 路径
|
||||
method: 'get',
|
||||
@ -166,7 +164,7 @@ export function deptAudit(id: string,roleId:string){
|
||||
}
|
||||
|
||||
// 获取验证码
|
||||
export function code(data: string){
|
||||
export function code(data: string) {
|
||||
return axios.get(`/api/rest/user/send-email?email=${data}`);
|
||||
}
|
||||
|
||||
@ -179,6 +177,5 @@ export function getUserDetail(id: number) {
|
||||
}
|
||||
|
||||
export function getMenuList() {
|
||||
return axios.post<RouteRecordNormalized[]>('/api/user/menu');
|
||||
return axios.get<RouteRecordNormalized[]>('/api/rest/user/menu');
|
||||
}
|
||||
|
||||
|
13344
src/assets/world.json
13344
src/assets/world.json
File diff suppressed because one or more lines are too long
@ -77,7 +77,7 @@
|
||||
itemData: {
|
||||
type: Object as PropType<TagProps>,
|
||||
default() {
|
||||
return [];
|
||||
return {};
|
||||
},
|
||||
},
|
||||
index: {
|
||||
|
@ -12,6 +12,6 @@
|
||||
"globalSettings": false,
|
||||
"device": "desktop",
|
||||
"tabBar": false,
|
||||
"menuFromServer": false,
|
||||
"menuFromServer": true,
|
||||
"serverMenu": []
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ function checkPermission(el: HTMLElement, binding: DirectiveBinding) {
|
||||
const { authorities } = userStore;
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
|
||||
if (value.length > 0) {
|
||||
const hasPermission = intersection(value, authorities).length > 0;
|
||||
|
||||
|
@ -6,32 +6,33 @@ export default function usePermission() {
|
||||
const userStore = useUserStore();
|
||||
return {
|
||||
accessRouter(route: RouteLocationNormalized | RouteRecordRaw) {
|
||||
|
||||
return (
|
||||
!route.meta?.requiresAuth ||
|
||||
!route.meta?.permissions ||
|
||||
route.meta?.permissions?.includes('*') ||
|
||||
intersection(route.meta?.permissions, userStore.permissions).length > 0
|
||||
|| route.meta?.permissions?.includes(userStore.permissions)
|
||||
intersection(route.meta?.permissions, userStore.permissions).length >
|
||||
0 ||
|
||||
route.meta?.permissions?.some((item) =>
|
||||
userStore?.permissions?.includes(item)
|
||||
)
|
||||
);
|
||||
},
|
||||
// TODO 不知道是干嘛的
|
||||
// findFirstPermissionRoute(_routers: any, role: string | string[] = 'admin') {
|
||||
// const cloneRouters = [..._routers];
|
||||
// while (cloneRouters.length) {
|
||||
// const firstElement = cloneRouters.shift();
|
||||
// if (
|
||||
// firstElement?.meta?.roles?.find((el: string[]) => {
|
||||
// return el.includes('*') || el.includes(role);
|
||||
// })
|
||||
// )
|
||||
// return { name: firstElement.name };
|
||||
// if (firstElement?.children) {
|
||||
// cloneRouters.push(...firstElement.children);
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
// },
|
||||
findFirstPermissionRoute(_routers: any, permissions: string[]) {
|
||||
const cloneRouters = [..._routers];
|
||||
while (cloneRouters.length) {
|
||||
const firstElement = cloneRouters.shift();
|
||||
if (
|
||||
firstElement?.meta?.roles?.find((el: string[]) => {
|
||||
return el.includes('*') || el.some((item) => permissions?.includes(item))
|
||||
})
|
||||
)
|
||||
return { name: firstElement.name };
|
||||
if (firstElement?.children) {
|
||||
cloneRouters.push(...firstElement.children);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// You can add any rules you want
|
||||
};
|
||||
}
|
||||
|
@ -5,10 +5,21 @@ import './message-box';
|
||||
|
||||
import '@/views/dashboard/workplace/mock';
|
||||
|
||||
import '@/views/dashboard/monitor/mock';
|
||||
|
||||
import '@/views/list/card/mock';
|
||||
import '@/views/list/search-table/mock';
|
||||
|
||||
import '@/views/form/step/mock';
|
||||
|
||||
import '@/views/profile/basic/mock';
|
||||
|
||||
import '@/views/visualization/data-analysis/mock';
|
||||
import '@/views/visualization/multi-dimension-data-analysis/mock';
|
||||
|
||||
import '@/views/user/info/mock';
|
||||
import '@/views/user/setting/mock';
|
||||
|
||||
|
||||
Mock.setup({
|
||||
timeout: '600-1000',
|
||||
});
|
||||
|
@ -2,12 +2,15 @@ import type { Router, RouteRecordNormalized } from 'vue-router';
|
||||
import NProgress from 'nprogress'; // progress bar
|
||||
|
||||
import usePermission from '@/hooks/permission';
|
||||
import { useAppStore } from '@/store';
|
||||
import { useAppStore, useUserStore } from '@/store';
|
||||
|
||||
import { appRoutes } from '../routes';
|
||||
import { WHITE_LIST, NOT_FOUND } from '../constants';
|
||||
|
||||
export default function setupPermissionGuard(router: Router) {
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
const Permission = usePermission();
|
||||
const permissionsAllow = Permission.accessRouter(to);
|
||||
|
||||
@ -44,8 +47,10 @@ export default function setupPermissionGuard(router: Router) {
|
||||
if (permissionsAllow) next();
|
||||
else {
|
||||
const destination =
|
||||
// Permission.findFirstPermissionRoute(appRoutes, userStore.permissions) ||
|
||||
NOT_FOUND;
|
||||
Permission.findFirstPermissionRoute(
|
||||
appRoutes,
|
||||
userStore.permissions
|
||||
) || NOT_FOUND;
|
||||
next(destination);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ export default function setupUserLoginInfoGuard(router: Router) {
|
||||
} else {
|
||||
try {
|
||||
await userStore.info();
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
await userStore.logout();
|
||||
|
@ -7,7 +7,6 @@ const DASHBOARD: AppRouteRecordRaw = {
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: 'menu.dashboard',
|
||||
title: '首页',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-dashboard', // 设置图标
|
||||
order: 0, // 排序路由菜单项。如果设置该值,值越高,越靠前
|
||||
@ -18,7 +17,7 @@ const DASHBOARD: AppRouteRecordRaw = {
|
||||
name: 'Workplace',
|
||||
component: () => import('@/views/dashboard/workplace/index.vue'),
|
||||
meta: {
|
||||
title: '工作台',
|
||||
locale: 'menu.dashboard.workplace',
|
||||
requiresAuth: true,
|
||||
permissions: ['*'],
|
||||
},
|
||||
|
37
src/router/routes/modules/notification.ts
Normal file
37
src/router/routes/modules/notification.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { DEFAULT_LAYOUT } from '../base';
|
||||
import { AppRouteRecordRaw } from '../types';
|
||||
|
||||
const NOTIFICATION: AppRouteRecordRaw = {
|
||||
path: '/notification',
|
||||
name: 'notification',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '通知管理',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-message', // 设置图标
|
||||
order: 0, // 排序路由菜单项。如果设置该值,值越高,越靠前
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'notice',
|
||||
name: 'notice',
|
||||
component: () => import('@/views/notification/notice/index.vue'),
|
||||
meta: {
|
||||
locale: '公告通知',
|
||||
requiresAuth: true,
|
||||
permissions: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'noticeSet',
|
||||
name: 'noticeSet',
|
||||
component: () => import('@/views/notification/noticeSet/index.vue'),
|
||||
meta: {
|
||||
locale: '公告管理',
|
||||
requiresAuth: true,
|
||||
permissions: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
export default NOTIFICATION;
|
@ -27,8 +27,6 @@ const SYSTEM: AppRouteRecordRaw = {
|
||||
name: 'Role',
|
||||
component: () => import('@/views/system/role/index.vue'),
|
||||
meta: {
|
||||
// locale: 'menu.system.role',
|
||||
title: '角色管理',
|
||||
requiresAuth: true,
|
||||
permissions: ['*'],
|
||||
},
|
||||
@ -38,8 +36,6 @@ const SYSTEM: AppRouteRecordRaw = {
|
||||
name: 'Dept',
|
||||
component: () => import('@/views/system/dept/index.vue'),
|
||||
meta: {
|
||||
// locale: 'menu.system.dept',
|
||||
title: '部门管理',
|
||||
requiresAuth: true,
|
||||
permissions: ['*'],
|
||||
},
|
||||
@ -49,19 +45,14 @@ const SYSTEM: AppRouteRecordRaw = {
|
||||
name: 'User',
|
||||
component: () => import('@/views/system/user/index.vue'),
|
||||
meta: {
|
||||
// locale: 'menu.system.user',
|
||||
title: '用户管理',
|
||||
requiresAuth: true,
|
||||
permissions: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'authority',
|
||||
name: 'Authority',
|
||||
component: () => import('@/views/system/authority/index.vue'),
|
||||
meta: {
|
||||
// locale: '权限管理',
|
||||
title: '权限管理',
|
||||
requiresAuth: true,
|
||||
permissions: ['*'],
|
||||
},
|
||||
|
@ -2,8 +2,8 @@ import { DEFAULT_LAYOUT } from '../base';
|
||||
import { AppRouteRecordRaw } from '../types';
|
||||
|
||||
const USER: AppRouteRecordRaw = {
|
||||
path: '/user',
|
||||
name: 'user',
|
||||
path: '/self',
|
||||
name: 'Self',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: 'menu.user',
|
||||
|
@ -6,10 +6,6 @@ import useTabBarStore from './modules/tab-bar';
|
||||
import useRoleStore from './modules/role';
|
||||
import useDeptStore from './modules/dept';
|
||||
import useAuthStore from './modules/auth';
|
||||
import useBulletinsStore from './modules/bulletins';
|
||||
import useBulletinStore from './modules/bulle-mgmt';
|
||||
import useMessagesStore from './modules/messages';
|
||||
import useMessageStore from './modules/message-mgmt';
|
||||
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersistedstate);
|
||||
@ -18,12 +14,8 @@ export {
|
||||
useAppStore,
|
||||
useUserStore,
|
||||
useTabBarStore,
|
||||
useRoleStore,
|
||||
useDeptStore,
|
||||
useRoleStore,
|
||||
useAuthStore,
|
||||
useBulletinsStore,
|
||||
useBulletinStore,
|
||||
useMessagesStore,
|
||||
useMessageStore,
|
||||
};
|
||||
export default pinia;
|
||||
|
@ -1,52 +1,55 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import {
|
||||
AuthCreateRecord,
|
||||
AuthRecord,
|
||||
create,
|
||||
queryAuthList,
|
||||
enabled,
|
||||
remove,
|
||||
update,
|
||||
getDetail
|
||||
} from '@/api/authority';
|
||||
import { authStore } from './type';
|
||||
AuthCreateRecord,
|
||||
AuthRecord,
|
||||
create,
|
||||
queryAuthList,
|
||||
enabled,
|
||||
remove,
|
||||
update,
|
||||
getDetail,
|
||||
} from '@/api/authority';
|
||||
import { authStore } from './type';
|
||||
|
||||
const useAuthStore = defineStore('auth', {
|
||||
state: (): authStore => ({
|
||||
id: undefined,
|
||||
remark: undefined,
|
||||
// createTime: undefined,
|
||||
name: undefined,
|
||||
enabled: undefined,
|
||||
}),
|
||||
const useAuthStore = defineStore('auth', {
|
||||
state: (): authStore => ({
|
||||
id: undefined,
|
||||
remark: undefined,
|
||||
// createTime: undefined,
|
||||
name: undefined,
|
||||
enabled: undefined,
|
||||
}),
|
||||
|
||||
getters: {
|
||||
AuthInfo(state: authStore): authStore {
|
||||
return { ...state };
|
||||
},
|
||||
getters: {
|
||||
AuthInfo(state: authStore): authStore {
|
||||
return { ...state };
|
||||
},
|
||||
actions: {
|
||||
// 获取所有的角色列表
|
||||
async getAuthList(data: AuthRecord) {
|
||||
return queryAuthList(data);
|
||||
},
|
||||
|
||||
async enabledAuth(id: string) {
|
||||
return enabled(id);
|
||||
},
|
||||
|
||||
async removeAuth(id: string) {
|
||||
return remove(id);
|
||||
},
|
||||
|
||||
async createAuth(params: AuthCreateRecord) {
|
||||
return create(params);
|
||||
},
|
||||
|
||||
async updateAuth(params: AuthRecord) {
|
||||
return update(params);
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
// 获取所有的角色列表
|
||||
async getAuthList(data: AuthRecord) {
|
||||
return queryAuthList(data);
|
||||
},
|
||||
});
|
||||
|
||||
export default useAuthStore;
|
||||
async enabledAuth(id: string) {
|
||||
return enabled(id);
|
||||
},
|
||||
|
||||
async removeAuth(id: string) {
|
||||
return remove(id);
|
||||
},
|
||||
|
||||
async createAuth(params: AuthCreateRecord) {
|
||||
return create(params);
|
||||
},
|
||||
|
||||
async updateAuth(params: AuthRecord) {
|
||||
return update(params);
|
||||
},
|
||||
async getAuthDetail(id: string) {
|
||||
return getDetail(id);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default useAuthStore;
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
update,
|
||||
userDetail,
|
||||
deptAudit,
|
||||
code
|
||||
code,
|
||||
} from '@/api/user';
|
||||
import { setToken, clearToken } from '@/utils/auth';
|
||||
import { removeRouteListener } from '@/utils/route-listener';
|
||||
@ -23,6 +23,7 @@ import useAppStore from '../app';
|
||||
|
||||
const useUserStore = defineStore('user', {
|
||||
state: (): UserState => ({
|
||||
id: undefined,
|
||||
username: undefined,
|
||||
nickName: undefined,
|
||||
avatar: undefined,
|
||||
@ -31,7 +32,6 @@ const useUserStore = defineStore('user', {
|
||||
address: undefined,
|
||||
createAt: undefined,
|
||||
remark: undefined,
|
||||
id: undefined,
|
||||
role: undefined,
|
||||
roles: undefined,
|
||||
permissions: [],
|
||||
@ -56,9 +56,9 @@ const useUserStore = defineStore('user', {
|
||||
},
|
||||
|
||||
async info() {
|
||||
const res = await getUserInfo();
|
||||
res.data.user.permissions = res.data.permissions;
|
||||
res.data.user.authorities = res.data.authorities;
|
||||
const res = await me();
|
||||
// res.data.user.permissions = res.data.permissions;
|
||||
// res.data.user.authorities = res.data.authorities;
|
||||
this.setInfo(res.data.user);
|
||||
},
|
||||
|
||||
@ -71,7 +71,9 @@ const useUserStore = defineStore('user', {
|
||||
async login(loginForm: LoginData, token: string) {
|
||||
try {
|
||||
setToken(token);
|
||||
await userLogin(loginForm);
|
||||
// await userLogin(loginForm);
|
||||
const res = await userLogin(loginForm);
|
||||
this.setInfo(res.data.user);
|
||||
} catch (err) {
|
||||
clearToken();
|
||||
throw err;
|
||||
@ -108,16 +110,16 @@ const useUserStore = defineStore('user', {
|
||||
return update(data);
|
||||
},
|
||||
|
||||
async getUserDetail(id: string){
|
||||
async getUserDetail(id: string) {
|
||||
return userDetail(id);
|
||||
},
|
||||
|
||||
async getDeptAudit(deptId: string,roleId: string){
|
||||
return deptAudit(deptId,roleId)
|
||||
async getDeptAudit(deptId: string, roleId: string) {
|
||||
return deptAudit(deptId, roleId);
|
||||
},
|
||||
|
||||
async getCode(params: string){
|
||||
return code(params)
|
||||
async getCode(params: string) {
|
||||
return code(params);
|
||||
},
|
||||
|
||||
logoutCallBack() {
|
||||
|
@ -13,6 +13,7 @@ export interface UserState {
|
||||
id?: number;
|
||||
role?: RoleRecord;
|
||||
roles?: RoleRecord[];
|
||||
permissions?: string[] | '' | '*' | 'admin' | 'user'|'auditor';
|
||||
authorities?: string[]
|
||||
// permissions?: string[] | '' | '*' | 'admin' | 'user' | 'auditor';
|
||||
permissions?: string[];
|
||||
authorities?: string[];
|
||||
}
|
||||
|
@ -1,67 +1,68 @@
|
||||
// 新建 @/utils/excel.ts
|
||||
|
||||
import saveAs from 'file-saver'; // https://www.npmjs.com/package/file-saver
|
||||
import ExcelJS from 'exceljs'; // https://github.com/exceljs/exceljs/blob/master/README_zh.md
|
||||
import * as XLSX from 'xlsx'; // https://www.npmjs.com/package/xlsx
|
||||
import { Message } from '@arco-design/web-vue'; // https://arco.design/vue/component/message
|
||||
import { FileItem } from '@arco-design/web-vue/es/upload/interfaces'; // arco类型
|
||||
|
||||
export interface DownloadExcelPrams {
|
||||
columns: { title: string, key: string }[];
|
||||
rows: object[];
|
||||
name: string
|
||||
}
|
||||
|
||||
// 导出下载文件
|
||||
export function downloadExcel({ columns, rows, name = '未命名文件' }: DownloadExcelPrams) {
|
||||
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
workbook.creator = 'Start-front';
|
||||
workbook.lastModifiedBy = 'Start-front';
|
||||
workbook.created = new Date(1985, 8, 30);
|
||||
workbook.modified = new Date();
|
||||
workbook.lastPrinted = new Date(2016, 9, 27);
|
||||
|
||||
// 将工作簿添加一个sheet页sheet1
|
||||
const sheet1 = workbook.addWorksheet(name);
|
||||
// 表头数据添加
|
||||
sheet1.columns = columns.map(item => ({
|
||||
header: item.title,
|
||||
key: item.key,
|
||||
width: 20
|
||||
}));
|
||||
// 表格内容添加
|
||||
rows.map(item => sheet1.addRow(item));
|
||||
workbook.xlsx.writeBuffer().then(buffer => {
|
||||
saveAs(
|
||||
new Blob([buffer], { type: 'application/octet-stream' }),
|
||||
`${name}.xlsx`
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 读取文件为json格式
|
||||
export function readExcle(fileItem:FileItem) {
|
||||
return new Promise((resove,reject)=>{
|
||||
try {
|
||||
let workbook:XLSX.Sheet;
|
||||
const reader = new FileReader();
|
||||
reader.readAsBinaryString(fileItem.file as File); // 发起异步请求
|
||||
reader.onload = function(ev){
|
||||
const data = ev.target?.result;
|
||||
workbook = XLSX.read(data, {type: 'binary'});
|
||||
const sheetNames = workbook.SheetNames; // 工作表名称集合
|
||||
sheetNames.forEach((name:string) => {
|
||||
const worksheet = workbook.Sheets[name]; // 只能通过工作表名称来获取指定工作表
|
||||
const jsonres = XLSX.utils.sheet_to_json(worksheet);
|
||||
resove(jsonres)
|
||||
});
|
||||
} // onload
|
||||
} catch (error) {
|
||||
Message.error('读取失败,请选择正确文件');
|
||||
reject(error);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// // 新建 @/utils/excel.ts
|
||||
//
|
||||
// import saveAs from 'file-saver'; // https://www.npmjs.com/package/file-saver
|
||||
// import ExcelJS from 'exceljs'; // https://github.com/exceljs/exceljs/blob/master/README_zh.md
|
||||
// import * as XLSX from 'xlsx'; // https://www.npmjs.com/package/xlsx
|
||||
// import { Message } from '@arco-design/web-vue'; // https://arco.design/vue/component/message
|
||||
// import { FileItem } from '@arco-design/web-vue/es/upload/interfaces'; // arco类型
|
||||
//
|
||||
// export interface DownloadExcelPrams {
|
||||
// columns: { title: string; key: string }[];
|
||||
// rows: object[];
|
||||
// name: string;
|
||||
// }
|
||||
//
|
||||
// // 导出下载文件
|
||||
// export function downloadExcel({
|
||||
// columns,
|
||||
// rows,
|
||||
// name = '未命名文件',
|
||||
// }: DownloadExcelPrams) {
|
||||
// const workbook = new ExcelJS.Workbook();
|
||||
// workbook.creator = 'Start-front';
|
||||
// workbook.lastModifiedBy = 'Start-front';
|
||||
// workbook.created = new Date(1985, 8, 30);
|
||||
// workbook.modified = new Date();
|
||||
// workbook.lastPrinted = new Date(2016, 9, 27);
|
||||
//
|
||||
// // 将工作簿添加一个sheet页sheet1
|
||||
// const sheet1 = workbook.addWorksheet(name);
|
||||
// // 表头数据添加
|
||||
// sheet1.columns = columns.map((item) => ({
|
||||
// header: item.title,
|
||||
// key: item.key,
|
||||
// width: 20,
|
||||
// }));
|
||||
// // 表格内容添加
|
||||
// rows.map((item) => sheet1.addRow(item));
|
||||
// workbook.xlsx.writeBuffer().then((buffer) => {
|
||||
// saveAs(
|
||||
// new Blob([buffer], { type: 'application/octet-stream' }),
|
||||
// `${name}.xlsx`
|
||||
// );
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// // 读取文件为json格式
|
||||
// export function readExcle(fileItem: FileItem) {
|
||||
// return new Promise((resove, reject) => {
|
||||
// try {
|
||||
// let workbook: XLSX.Sheet;
|
||||
// const reader = new FileReader();
|
||||
// reader.readAsBinaryString(fileItem.file as File); // 发起异步请求
|
||||
// reader.onload = function (ev) {
|
||||
// const data = ev.target?.result;
|
||||
// workbook = XLSX.read(data, { type: 'binary' });
|
||||
// const sheetNames = workbook.SheetNames; // 工作表名称集合
|
||||
// sheetNames.forEach((name: string) => {
|
||||
// const worksheet = workbook.Sheets[name]; // 只能通过工作表名称来获取指定工作表
|
||||
// const jsonres = XLSX.utils.sheet_to_json(worksheet);
|
||||
// resove(jsonres);
|
||||
// });
|
||||
// }; // onload
|
||||
// } catch (error) {
|
||||
// Message.error('读取失败,请选择正确文件');
|
||||
// reject(error);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
@ -1,108 +1,150 @@
|
||||
<template>
|
||||
<a-grid :cols="24" :row-gap="16" class="panel">
|
||||
<a-grid-item
|
||||
class="panel-col"
|
||||
:span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }"
|
||||
>
|
||||
<a-space>
|
||||
<a-avatar :size="54" class="col-avatar">
|
||||
<img
|
||||
alt="avatar"
|
||||
src="//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/288b89194e657603ff40db39e8072640.svg~tplv-49unhts6dw-image.image"
|
||||
/>
|
||||
</a-avatar>
|
||||
<a-statistic
|
||||
:title="$t('workplace.onlineContent')"
|
||||
:value="373.5"
|
||||
:precision="1"
|
||||
:value-from="0"
|
||||
animation
|
||||
show-group-separator
|
||||
>
|
||||
<template #suffix>
|
||||
W+ <span class="unit">{{ $t('workplace.pecs') }}</span>
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-space>
|
||||
</a-grid-item>
|
||||
<a-grid-item
|
||||
class="panel-col"
|
||||
:span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }"
|
||||
>
|
||||
<a-space>
|
||||
<a-avatar :size="54" class="col-avatar">
|
||||
<img
|
||||
alt="avatar"
|
||||
src="//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/fdc66b07224cdf18843c6076c2587eb5.svg~tplv-49unhts6dw-image.image"
|
||||
/>
|
||||
</a-avatar>
|
||||
<a-statistic
|
||||
:title="$t('workplace.putIn')"
|
||||
:value="368"
|
||||
:value-from="0"
|
||||
animation
|
||||
show-group-separator
|
||||
>
|
||||
<template #suffix>
|
||||
<span class="unit">{{ $t('workplace.pecs') }}</span>
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-space>
|
||||
</a-grid-item>
|
||||
<a-grid-item
|
||||
class="panel-col"
|
||||
:span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }"
|
||||
>
|
||||
<a-space>
|
||||
<a-avatar :size="54" class="col-avatar">
|
||||
<img
|
||||
alt="avatar"
|
||||
src="//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/77d74c9a245adeae1ec7fb5d4539738d.svg~tplv-49unhts6dw-image.image"
|
||||
/>
|
||||
</a-avatar>
|
||||
<a-statistic
|
||||
:title="$t('workplace.newDay')"
|
||||
:value="8874"
|
||||
:value-from="0"
|
||||
animation
|
||||
show-group-separator
|
||||
>
|
||||
<template #suffix>
|
||||
<span class="unit">{{ $t('workplace.pecs') }}</span>
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-space>
|
||||
</a-grid-item>
|
||||
<a-grid-item
|
||||
class="panel-col"
|
||||
:span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }"
|
||||
style="border-right: none"
|
||||
>
|
||||
<a-space>
|
||||
<a-avatar :size="54" class="col-avatar">
|
||||
<img
|
||||
alt="avatar"
|
||||
src="//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/c8b36e26d2b9bb5dbf9b74dd6d7345af.svg~tplv-49unhts6dw-image.image"
|
||||
/>
|
||||
</a-avatar>
|
||||
<a-statistic
|
||||
:title="$t('workplace.newFromYesterday')"
|
||||
:value="2.8"
|
||||
:precision="1"
|
||||
:value-from="0"
|
||||
animation
|
||||
>
|
||||
<template #suffix> % <icon-caret-up class="up-icon" /> </template>
|
||||
</a-statistic>
|
||||
</a-space>
|
||||
</a-grid-item>
|
||||
<a-grid-item :span="24">
|
||||
<a-divider class="panel-border" />
|
||||
</a-grid-item>
|
||||
</a-grid>
|
||||
<div style="width: 100%">
|
||||
<a-grid :cols="24" :row-gap="16" class="panel">
|
||||
<a-grid-item
|
||||
class="panel-col"
|
||||
:span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }"
|
||||
>
|
||||
<a-space @click="to('PASS')">
|
||||
<a-avatar :size="54" class="col-avatar">
|
||||
<img
|
||||
alt="avatar"
|
||||
src="//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/288b89194e657603ff40db39e8072640.svg~tplv-49unhts6dw-image.image"
|
||||
/>
|
||||
</a-avatar>
|
||||
<a-statistic
|
||||
:title="$t('workplace.pass')"
|
||||
:value="formData.pass || 0"
|
||||
:value-from="0"
|
||||
show-group-separator
|
||||
>
|
||||
<template #suffix>
|
||||
<span class="unit">{{ $t('workplace.pecs') }}</span>
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-space>
|
||||
</a-grid-item>
|
||||
<a-grid-item
|
||||
class="panel-col"
|
||||
:span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }"
|
||||
>
|
||||
<a-space @click="to('FAILED')">
|
||||
<a-avatar :size="54" class="col-avatar">
|
||||
<img
|
||||
alt="avatar"
|
||||
src="//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/fdc66b07224cdf18843c6076c2587eb5.svg~tplv-49unhts6dw-image.image"
|
||||
/>
|
||||
</a-avatar>
|
||||
<a-statistic
|
||||
:title="$t('workplace.notPass')"
|
||||
:value="formData.notPass || 0"
|
||||
:value-from="0"
|
||||
show-group-separator
|
||||
>
|
||||
<template #suffix>
|
||||
<span class="unit">{{ $t('workplace.pecs') }}</span>
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-space>
|
||||
</a-grid-item>
|
||||
<a-grid-item
|
||||
class="panel-col"
|
||||
:span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }"
|
||||
>
|
||||
<a-space @click="to('EXAMINE')">
|
||||
<a-avatar :size="54" class="col-avatar">
|
||||
<img
|
||||
alt="avatar"
|
||||
src="//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/77d74c9a245adeae1ec7fb5d4539738d.svg~tplv-49unhts6dw-image.image"
|
||||
/>
|
||||
</a-avatar>
|
||||
<a-statistic
|
||||
:title="$t('workplace.notAudit')"
|
||||
:value="formData.notAudit || 0"
|
||||
:value-from="0"
|
||||
show-group-separator
|
||||
>
|
||||
<template #suffix>
|
||||
<span class="unit">{{ $t('workplace.pecs') }}</span>
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-space>
|
||||
</a-grid-item>
|
||||
<a-grid-item
|
||||
v-if="userStore.permissions !== 'auditor'"
|
||||
class="panel-col"
|
||||
:span="{ xs: 12, sm: 12, md: 12, lg: 12, xl: 12, xxl: 6 }"
|
||||
style="border-right: none"
|
||||
>
|
||||
<a-space @click="to('SUBMIT')">
|
||||
<a-avatar :size="54" class="col-avatar">
|
||||
<img
|
||||
alt="avatar"
|
||||
src="//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/c8b36e26d2b9bb5dbf9b74dd6d7345af.svg~tplv-49unhts6dw-image.image"
|
||||
/>
|
||||
</a-avatar>
|
||||
<a-statistic
|
||||
v-model="formData.notFiled"
|
||||
:title="$t('workplace.notFiled')"
|
||||
:value="formData.notFiled || 0"
|
||||
:value-from="0"
|
||||
show-group-separator
|
||||
>
|
||||
<template #suffix>
|
||||
<span class="unit">{{ $t('workplace.pecs') }}</span>
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-space>
|
||||
</a-grid-item>
|
||||
<a-grid-item :span="24">
|
||||
<a-divider class="panel-border" />
|
||||
</a-grid-item>
|
||||
</a-grid>
|
||||
<a-card :bordered="false">
|
||||
<a-space id="TicketEcharts" style="width: 98%; height: 400px"></a-space>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup></script>
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useUserStore } from '@/store';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import router from '@/router';
|
||||
|
||||
const { t } = useI18n();
|
||||
const userStore = useUserStore();
|
||||
const formData = ref({
|
||||
notAudit: undefined,
|
||||
notFiled: undefined,
|
||||
notPass: undefined,
|
||||
pass: undefined,
|
||||
});
|
||||
|
||||
const getHomeData = async (params: {
|
||||
auditorId: number | undefined;
|
||||
userId: number | string | undefined;
|
||||
}) => {
|
||||
if (userStore.permissions === 'admin') {
|
||||
params.userId = '';
|
||||
} else if (userStore.permissions === 'auditor') {
|
||||
params.auditorId = userStore.id;
|
||||
} else if (userStore.permissions === 'user') {
|
||||
params.userId = userStore.id;
|
||||
}
|
||||
};
|
||||
|
||||
const to = (key: string) => {
|
||||
router.push({
|
||||
name: 'TicketManage',
|
||||
query: {
|
||||
status: key,
|
||||
},
|
||||
});
|
||||
};
|
||||
getHomeData({});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.arco-grid.panel {
|
||||
|
@ -15,70 +15,70 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import bannerImage from '@/assets/images/login-banner.png';
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import bannerImage from '@/assets/images/login-banner.png';
|
||||
|
||||
const { t } = useI18n();
|
||||
const carouselItem = computed(() => [
|
||||
{
|
||||
slogan: t('login.banner.slogan1'),
|
||||
subSlogan: t('login.banner.subSlogan1'),
|
||||
image: bannerImage,
|
||||
},
|
||||
{
|
||||
slogan: t('login.banner.slogan2'),
|
||||
subSlogan: t('login.banner.subSlogan2'),
|
||||
image: bannerImage,
|
||||
},
|
||||
{
|
||||
slogan: t('login.banner.slogan3'),
|
||||
subSlogan: t('login.banner.subSlogan3'),
|
||||
image: bannerImage,
|
||||
},
|
||||
]);
|
||||
const { t } = useI18n();
|
||||
const carouselItem = computed(() => [
|
||||
{
|
||||
slogan: t('login.banner.slogan1'),
|
||||
subSlogan: t('login.banner.subSlogan1'),
|
||||
image: bannerImage,
|
||||
},
|
||||
{
|
||||
slogan: t('login.banner.slogan2'),
|
||||
subSlogan: t('login.banner.subSlogan2'),
|
||||
image: bannerImage,
|
||||
},
|
||||
{
|
||||
slogan: t('login.banner.slogan3'),
|
||||
subSlogan: t('login.banner.subSlogan3'),
|
||||
image: bannerImage,
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&-inner {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.carousel {
|
||||
height: 100%;
|
||||
|
||||
&-item {
|
||||
.banner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&-inner {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.carousel {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&-title {
|
||||
color: var(--color-fill-1);
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
}
|
||||
&-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&-sub-title {
|
||||
margin-top: 8px;
|
||||
color: var(--color-text-3);
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
&-title {
|
||||
color: var(--color-fill-1);
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
&-image {
|
||||
width: 320px;
|
||||
margin-top: 30px;
|
||||
&-sub-title {
|
||||
margin-top: 8px;
|
||||
color: var(--color-text-3);
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
&-image {
|
||||
width: 320px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="login-form-wrapper">
|
||||
<div class="login-form-title">物联网网关系统</div>
|
||||
<div class="login-form-title">{{ $t('login.form.title') }}</div>
|
||||
<!-- <div class="login-form-sub-title">{{ $t('login.form.title') }}</div>-->
|
||||
<!-- <div class="login-form-sub-title">请先登录</div>-->
|
||||
<div class="login-form-error-msg">{{ errorMessage }}</div>
|
||||
@ -170,9 +170,9 @@
|
||||
<a-button
|
||||
type="primary"
|
||||
style="margin-left: 50px; margin-right: 50px"
|
||||
@click="getCodeData"
|
||||
:disabled="flag"
|
||||
>
|
||||
@click="getCodeData"
|
||||
>
|
||||
<!-- 发送验证码 -->
|
||||
<div v-if="flag">({{ totalCount }}s)</div>
|
||||
</a-button>
|
||||
@ -182,195 +182,195 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import useVisible from '@/hooks/visible';
|
||||
import { FormInstance } from '@arco-design/web-vue/es/form';
|
||||
import { ref, reactive } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { ValidatedError } from '@arco-design/web-vue/es/form/interface';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useStorage } from '@vueuse/core';
|
||||
import { useUserStore } from '@/store';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import { LoginData, CreateRecord } from '@/api/user';
|
||||
import useVisible from '@/hooks/visible';
|
||||
import { FormInstance } from '@arco-design/web-vue/es/form';
|
||||
import { ref, reactive } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { ValidatedError } from '@arco-design/web-vue/es/form/interface';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useStorage } from '@vueuse/core';
|
||||
import { useUserStore } from '@/store';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import { LoginData, CreateRecord } from '@/api/user';
|
||||
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
const errorMessage = ref('');
|
||||
const { loading, setLoading } = useLoading();
|
||||
const userStore = useUserStore();
|
||||
const { visible, setVisible } = useVisible(false);
|
||||
const userCreateRef = ref<FormInstance>();
|
||||
const modalTitle = t('create.user');
|
||||
const formData = ref<CreateRecord>({
|
||||
username: '',
|
||||
nickName: '',
|
||||
password: '',
|
||||
phone: '',
|
||||
email: '@qq.com',
|
||||
enabled: 'true',
|
||||
address: '',
|
||||
deptId: 235,
|
||||
roleId: undefined,
|
||||
permissionIds: [],
|
||||
authorities: [],
|
||||
code: '',
|
||||
});
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
const errorMessage = ref('');
|
||||
const { loading, setLoading } = useLoading();
|
||||
const userStore = useUserStore();
|
||||
const { visible, setVisible } = useVisible(false);
|
||||
const userCreateRef = ref<FormInstance>();
|
||||
const modalTitle = t('create.user');
|
||||
const formData = ref<CreateRecord>({
|
||||
username: '',
|
||||
nickName: '',
|
||||
password: '',
|
||||
phone: '',
|
||||
email: '@qq.com',
|
||||
enabled: 'true',
|
||||
address: '',
|
||||
deptId: 235,
|
||||
roleId: undefined,
|
||||
permissionIds: [],
|
||||
authorities: [],
|
||||
code: '',
|
||||
});
|
||||
|
||||
const flag = ref(false);
|
||||
const totalCount = ref(60);
|
||||
const flag = ref(false);
|
||||
const totalCount = ref(60);
|
||||
|
||||
const loginConfig = useStorage('login-config', {
|
||||
// 使用 useStorage 创建一个响应式变量,存储登录相关配置
|
||||
rememberPassword: true,
|
||||
username: '', // 演示默认值
|
||||
password: '', // demo default value
|
||||
});
|
||||
const loginConfig = useStorage('login-config', {
|
||||
// 使用 useStorage 创建一个响应式变量,存储登录相关配置
|
||||
rememberPassword: true,
|
||||
username: '', // 演示默认值
|
||||
password: '', // demo default value
|
||||
});
|
||||
|
||||
const userInfo = reactive({
|
||||
// 创建一个响应式对象,反映 loginConfig 中的 username 和 password
|
||||
username: loginConfig.value.username,
|
||||
password: loginConfig.value.password,
|
||||
});
|
||||
const userInfo = reactive({
|
||||
// 创建一个响应式对象,反映 loginConfig 中的 username 和 password
|
||||
username: loginConfig.value.username,
|
||||
password: loginConfig.value.password,
|
||||
});
|
||||
|
||||
// 登录
|
||||
const handleSubmit = async ({
|
||||
// 处理表单提交的异步函数
|
||||
errors,
|
||||
values,
|
||||
}: {
|
||||
errors: Record<string, ValidatedError> | undefined;
|
||||
values: Record<string, any>;
|
||||
}) => {
|
||||
// 如果正在加载中,提前返回
|
||||
if (loading.value) return;
|
||||
// 登录
|
||||
const handleSubmit = async ({
|
||||
// 处理表单提交的异步函数
|
||||
errors,
|
||||
values,
|
||||
}: {
|
||||
errors: Record<string, ValidatedError> | undefined;
|
||||
values: Record<string, any>;
|
||||
}) => {
|
||||
// 如果正在加载中,提前返回
|
||||
if (loading.value) return;
|
||||
|
||||
// 如果没有表单验证错误
|
||||
if (!errors) {
|
||||
setLoading(true);
|
||||
// 如果没有表单验证错误
|
||||
if (!errors) {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const res = await userStore.me();
|
||||
await userStore.login(values as LoginData, res.data.csrf.token);
|
||||
await userStore.me();
|
||||
await userStore.info();
|
||||
// 获取路由信息,处理重定向
|
||||
const { ...othersQuery } = router.currentRoute.value.query;
|
||||
router.push({
|
||||
name: 'Workplace',
|
||||
query: {
|
||||
...othersQuery,
|
||||
},
|
||||
});
|
||||
try {
|
||||
const res = await userStore.me();
|
||||
await userStore.login(values as LoginData, res.data.csrf.token);
|
||||
// await userStore.me();
|
||||
// await userStore.info();
|
||||
// 获取路由信息,处理重定向
|
||||
const { ...othersQuery } = router.currentRoute.value.query;
|
||||
router.push({
|
||||
name: 'Workplace',
|
||||
query: {
|
||||
...othersQuery,
|
||||
},
|
||||
});
|
||||
|
||||
// 显示登录成功的消息
|
||||
Message.success(t('login.form.login.success'));
|
||||
const { rememberPassword } = loginConfig.value;
|
||||
const { username, password } = values;
|
||||
// 显示登录成功的消息
|
||||
Message.success(t('login.form.login.success'));
|
||||
const { rememberPassword } = loginConfig.value;
|
||||
const { username, password } = values;
|
||||
|
||||
// 实际生产环境需要进行加密存储。
|
||||
// The actual production environment requires encrypted storage.
|
||||
loginConfig.value.username = rememberPassword ? username : '';
|
||||
loginConfig.value.password = rememberPassword ? password : '';
|
||||
} catch (err) {
|
||||
// errorMessage.value = (err as Error).message;
|
||||
errorMessage.value = t('login.form.login.errMsg');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
// 实际生产环境需要进行加密存储。
|
||||
// The actual production environment requires encrypted storage.
|
||||
loginConfig.value.username = rememberPassword ? username : '';
|
||||
loginConfig.value.password = rememberPassword ? password : '';
|
||||
} catch (err) {
|
||||
// errorMessage.value = (err as Error).message;
|
||||
errorMessage.value = t('login.form.login.errMsg');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 记住密码
|
||||
const setRememberPassword = (value: boolean) => {
|
||||
loginConfig.value.rememberPassword = value;
|
||||
};
|
||||
// 记住密码
|
||||
const setRememberPassword = (value: boolean) => {
|
||||
loginConfig.value.rememberPassword = value;
|
||||
};
|
||||
|
||||
// 打开弹窗
|
||||
const handleClick = () => {
|
||||
setVisible(true);
|
||||
};
|
||||
// 打开弹窗
|
||||
const handleClick = () => {
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
// 关闭弹窗
|
||||
const handleCancel = async () => {
|
||||
userCreateRef.value?.resetFields();
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
// 获取验证码
|
||||
const getCodeData = async () => {
|
||||
if (formData.value.email === '') {
|
||||
Message.error({
|
||||
content: t('user.info.email.required'),
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
} else {
|
||||
const res = await userStore.getCode(formData.value.email);
|
||||
if (res.status === 200) {
|
||||
flag.value = true;
|
||||
setInterval(() => {
|
||||
if (totalCount.value !== 0) {
|
||||
totalCount.value = totalCount.value * 1 - 1;
|
||||
}
|
||||
}, 1000);
|
||||
setTimeout(() => {
|
||||
flag.value = false;
|
||||
totalCount.value = 60;
|
||||
}, 60000);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 提交注册
|
||||
const handleOk = async () => {
|
||||
const valid = await userCreateRef.value?.validate();
|
||||
if (!valid) {
|
||||
// formData.value.username = formData.value.email;
|
||||
const res = await userStore.registerUser(formData.value);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('create.sucess'),
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
}
|
||||
// 关闭弹窗
|
||||
const handleCancel = async () => {
|
||||
userCreateRef.value?.resetFields();
|
||||
setVisible(false);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 获取验证码
|
||||
const getCodeData = async () => {
|
||||
if (formData.value.email === '') {
|
||||
Message.error({
|
||||
content: t('user.info.email.required'),
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
} else {
|
||||
const res = await userStore.getCode(formData.value.email);
|
||||
if (res.status === 200) {
|
||||
flag.value = true;
|
||||
setInterval(() => {
|
||||
if (totalCount.value !== 0) {
|
||||
totalCount.value = totalCount.value * 1 - 1;
|
||||
}
|
||||
}, 1000);
|
||||
setTimeout(() => {
|
||||
flag.value = false;
|
||||
totalCount.value = 60;
|
||||
}, 60000);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 提交注册
|
||||
const handleOk = async () => {
|
||||
const valid = await userCreateRef.value?.validate();
|
||||
if (!valid) {
|
||||
// formData.value.username = formData.value.email;
|
||||
const res = await userStore.registerUser(formData.value);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('create.sucess'),
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
}
|
||||
userCreateRef.value?.resetFields();
|
||||
setVisible(false);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.login-form {
|
||||
&-wrapper {
|
||||
width: 320px;
|
||||
}
|
||||
.login-form {
|
||||
&-wrapper {
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
&-title {
|
||||
color: var(--color-text-1);
|
||||
font-weight: 500;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
}
|
||||
&-title {
|
||||
color: var(--color-text-1);
|
||||
font-weight: 500;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
&-sub-title {
|
||||
color: var(--color-text-3);
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
&-sub-title {
|
||||
color: var(--color-text-3);
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
&-error-msg {
|
||||
height: 32px;
|
||||
color: rgb(var(--red-6));
|
||||
line-height: 32px;
|
||||
}
|
||||
&-error-msg {
|
||||
height: 32px;
|
||||
color: rgb(var(--red-6));
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
&-password-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
&-password-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&-register-btn {
|
||||
color: var(--color-text-3) !important;
|
||||
&-register-btn {
|
||||
color: var(--color-text-3) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="logo">
|
||||
<div class="logo-text">Hello!</div>
|
||||
<div class="logo-text">Hello Ticket!</div>
|
||||
</div>
|
||||
<LoginBanner />
|
||||
<div class="content">
|
||||
@ -13,61 +13,61 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import LoginBanner from './components/banner.vue';
|
||||
import LoginForm from './components/login-form.vue';
|
||||
import LoginBanner from './components/banner.vue';
|
||||
import LoginForm from './components/login-form.vue';
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
|
||||
.banner {
|
||||
width: 550px;
|
||||
background: linear-gradient(163.85deg, #1d2129 0%, #00308f 100%);
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
.container {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
height: 100vh;
|
||||
|
||||
.banner {
|
||||
width: 550px;
|
||||
background: linear-gradient(163.85deg, #1d2129 0%, #00308f 100%);
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
position: fixed;
|
||||
top: 24px;
|
||||
left: 22px;
|
||||
z-index: 1;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
&-text {
|
||||
margin-right: 4px;
|
||||
margin-left: 4px;
|
||||
color: var(--color-fill-1);
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
position: fixed;
|
||||
top: 24px;
|
||||
left: 22px;
|
||||
z-index: 1;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
&-text {
|
||||
margin-right: 4px;
|
||||
margin-left: 4px;
|
||||
color: var(--color-fill-1);
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// responsive
|
||||
@media (max-width: @screen-lg) {
|
||||
.container {
|
||||
.banner {
|
||||
width: 25%;
|
||||
// responsive
|
||||
@media (max-width: @screen-lg) {
|
||||
.container {
|
||||
.banner {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
355
src/views/notification/notice/index.vue
Normal file
355
src/views/notification/notice/index.vue
Normal file
@ -0,0 +1,355 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<Breadcrumb :items="['通知管理', '公告通知']" />
|
||||
<a-card class="general-card" title=" ">
|
||||
<a-row>
|
||||
<a-col :flex="1">
|
||||
<a-form
|
||||
:model="formModel"
|
||||
:label-col-props="{ span: 6 }"
|
||||
:wrapper-col-props="{ span: 18 }"
|
||||
label-align="right"
|
||||
>
|
||||
<a-row :gutter="18">
|
||||
<a-col :span="9">
|
||||
<a-form-item field="title" :label="$t('标题')">
|
||||
<a-input
|
||||
v-model="formModel.title"
|
||||
style="width: 360px"
|
||||
:placeholder="$t('请输入标题')"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="9">
|
||||
<a-form-item field="enable" :label="$t('状态')">
|
||||
<a-select
|
||||
v-model="formModel.states"
|
||||
style="width: 360px"
|
||||
:placeholder="$t('请选择状态')"
|
||||
:options="statusOptions"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="9">
|
||||
<a-form-item field="publishTimeBegin" :label="$t('开始时间')">
|
||||
<a-date-picker
|
||||
v-model="formModel.publishTimeBegin"
|
||||
style="width: 360px"
|
||||
show-time
|
||||
:time-picker-props="{ defaultValue: '09:09:06' }"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
:allow-clear="false"
|
||||
@select="onSelect"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="9">
|
||||
<a-form-item field="publishTimeEnd" :label="$t('结束时间')">
|
||||
<a-date-picker
|
||||
v-model="formModel.publishTimeEnd"
|
||||
style="width: 360px"
|
||||
show-time
|
||||
:time-picker-props="{ defaultValue: '09:09:06' }"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
:allow-clear="false"
|
||||
@select="onSelect"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-col>
|
||||
<a-divider style="height: 84px" direction="vertical" />
|
||||
<a-col :flex="'46px'" style="text-align: right">
|
||||
<a-space direction="vertical" :size="18">
|
||||
<a-button type="primary" @click="search">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
{{ $t('searchTable.form.search') }}
|
||||
</a-button>
|
||||
<a-button @click="reset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
{{ $t('searchTable.form.reset') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-divider style="margin-top: 0" />
|
||||
|
||||
<a-table
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:pagination="false"
|
||||
:columns="(cloneColumns as TableColumnData[])"
|
||||
:data="renderData"
|
||||
:bordered="false"
|
||||
:size="size"
|
||||
style="margin-bottom: 40px"
|
||||
:filter-icon-align-left="alignLeft"
|
||||
@change="handleSortChange"
|
||||
@page-change="onPageChange"
|
||||
>
|
||||
<template #index="{ rowIndex }">
|
||||
{{ rowIndex + 1 + (pagination.current - 1) * pagination.size }}
|
||||
</template>
|
||||
<template #enabled="{ record }">
|
||||
<a-switch
|
||||
:model-value="record.enabled"
|
||||
:checked-value="true"
|
||||
:unchecked-value="false"
|
||||
@change="enabledStatus(record)"
|
||||
/>
|
||||
</template>
|
||||
<template #operations="{ record }">
|
||||
<a-button
|
||||
type="outline"
|
||||
size="small"
|
||||
status="success"
|
||||
:prem="record"
|
||||
style="padding: 7px; margin-right: 10px"
|
||||
>
|
||||
<template #icon><icon-list /></template>
|
||||
详情
|
||||
</a-button>
|
||||
</template>
|
||||
</a-table>
|
||||
<a-pagination
|
||||
style="float: right; position: relative; right: 1px; bottom: 25px"
|
||||
:total="pagination.total"
|
||||
:size="size"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
@page-size-change="onSizeChange"
|
||||
@change="onPageChange"
|
||||
/>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import { UserRecord, UserParams } from '@/api/user';
|
||||
import { Pagination } from '@/types/global';
|
||||
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
|
||||
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
|
||||
import { useUserStore } from '@/store';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import useTableOption from '@/hooks/table-option';
|
||||
import NoticeEdit from '@/views/notification/noticeSet/components/notice-edit.vue';
|
||||
|
||||
const generateFormModel = () => {
|
||||
return {
|
||||
title: '',
|
||||
states: '',
|
||||
publishTimeBegin: '',
|
||||
publishTimeEnd: '',
|
||||
};
|
||||
};
|
||||
|
||||
const { loading, setLoading } = useLoading(true);
|
||||
const { t } = useI18n();
|
||||
const renderData = ref<UserRecord[]>([]);
|
||||
const formModel = ref(generateFormModel());
|
||||
|
||||
const {
|
||||
cloneColumns,
|
||||
showColumns,
|
||||
densityList,
|
||||
handleSelectDensity,
|
||||
handleChange,
|
||||
popupVisibleChange,
|
||||
deepClone,
|
||||
} = useTableOption();
|
||||
const sizeof = useTableOption().size;
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const pagination: Pagination = {
|
||||
page: 1,
|
||||
size: 10,
|
||||
current: 1,
|
||||
total: null,
|
||||
};
|
||||
|
||||
const columns = computed<TableColumnData[]>(() => [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
slotName: 'index',
|
||||
width: 60,
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
dataIndex: 'title',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('时间'),
|
||||
dataIndex: 'publishTimeBegin',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('状态'),
|
||||
dataIndex: 'states',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operations',
|
||||
slotName: 'operations',
|
||||
},
|
||||
]);
|
||||
const statusOptions = computed<SelectOptionData[]>(() => [
|
||||
{
|
||||
label: t('已发布'),
|
||||
value: 'true',
|
||||
},
|
||||
{
|
||||
label: t('未发布'),
|
||||
value: 'false',
|
||||
},
|
||||
]);
|
||||
|
||||
// 获取公告列表
|
||||
const fetchData = async (
|
||||
params: UserParams = { page: 1, size: 10, current: 1 }
|
||||
) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await userStore.getUserList(params);
|
||||
renderData.value = res.data.records;
|
||||
pagination.page = res.data.page;
|
||||
pagination.current = res.data.current;
|
||||
pagination.total = res.data.total;
|
||||
pagination.size = res.data.size;
|
||||
} catch (err) {
|
||||
// you can report use errorHandler or other
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 查询
|
||||
const search = () => {
|
||||
fetchData({
|
||||
...pagination,
|
||||
...formModel.value,
|
||||
} as unknown as UserParams);
|
||||
};
|
||||
|
||||
// 分页发生改变
|
||||
const onPageChange = (current: number) => {
|
||||
pagination.page = current;
|
||||
pagination.current = current;
|
||||
search();
|
||||
};
|
||||
|
||||
// 数据条数改变
|
||||
const onSizeChange = (size: number) => {
|
||||
pagination.size = size;
|
||||
search();
|
||||
};
|
||||
|
||||
search();
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
formModel.value = generateFormModel();
|
||||
};
|
||||
|
||||
// 表格内部排序
|
||||
const alignLeft = ref(false);
|
||||
const handleSortChange = (
|
||||
data: any,
|
||||
extra: any,
|
||||
currentDataSource: any
|
||||
) => {};
|
||||
|
||||
// 是否启用
|
||||
const enabledStatus = async (record: string) => {
|
||||
record.enabled = !record.enabled;
|
||||
const res = await userStore.enabledUser(record.id);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('modify.status.sucess'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
} else {
|
||||
Message.error({
|
||||
content: t('modify.status.fail'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 删除
|
||||
// const handleDelete = async (record: UserRecord) => {
|
||||
// const res = await userStore.removeUser(record.id);
|
||||
// if (res.status === 200) {
|
||||
// Message.success({
|
||||
// content: '删除成功',
|
||||
// duration: 5 * 1000,
|
||||
// });
|
||||
// search();
|
||||
// }
|
||||
// };
|
||||
|
||||
watch(() => columns.value, deepClone, { deep: true, immediate: true });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
padding: 0 20px 20px 20px;
|
||||
}
|
||||
|
||||
.content-col {
|
||||
flex: 1;
|
||||
padding-left: 24px; /* 左侧内边距 */
|
||||
}
|
||||
|
||||
.message-item {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
|
||||
margin-bottom: 16px; /* 卡片之间的间距 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.scroll-wrapper {
|
||||
height: calc(62vh); /* 调整高度以适应页面布局 */
|
||||
overflow-y: auto; /* 当内容超出时显示滚动条 */
|
||||
border: 1px solid #d9d9d9; /* 边框颜色调淡 */
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.load-trigger {
|
||||
height: 1px; /* 设置高度为1px,使其不占据太多空间 */
|
||||
opacity: 0; /* 使其不可见 */
|
||||
}
|
||||
|
||||
.loading,
|
||||
.no-more {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
208
src/views/notification/noticeSet/components/notice-edit.vue
Normal file
208
src/views/notification/noticeSet/components/notice-edit.vue
Normal file
@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<a-button v-if="props.isCreate" type="primary">
|
||||
<template #icon><icon-plus /></template>
|
||||
新建
|
||||
</a-button>
|
||||
<a-button
|
||||
v-if="!props.isCreate"
|
||||
type="outline"
|
||||
size="small"
|
||||
:style="{ marginRight: '10px', padding: '7px' }"
|
||||
>
|
||||
<template #icon><icon-edit /></template>
|
||||
修改
|
||||
</a-button>
|
||||
|
||||
<a-modal
|
||||
width="700px"
|
||||
:visible="visible"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<template #title>{{ modalTitle }}</template>
|
||||
<a-form ref="CreateRef" :model="formData" :style="{ width: '650px' }">
|
||||
<a-form-item
|
||||
field="title"
|
||||
:label="$t('标题')"
|
||||
:validate-trigger="['change', 'input']"
|
||||
:rules="[
|
||||
{ required: true, message: '' },
|
||||
{
|
||||
match: /^[a-zA-Z0-9\u4e00-\u9fa5]{1,20}$/,
|
||||
message: '',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<a-input v-model="formData.title" :placeholder="$t('请输入公告标题')" />
|
||||
<!-- v-if="props.isCreate"-->
|
||||
<!-- <div v-else>{{ formData.title }}</div>-->
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
field="email"
|
||||
:label="$t('作者')"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
type: 'email',
|
||||
message: t('user.info.email.required'),
|
||||
},
|
||||
]"
|
||||
:validate-trigger="['change', 'input']"
|
||||
>
|
||||
<a-input v-model="formData.email" :placeholder="$t('请输入作者')" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
field="phone"
|
||||
:label="$t('发布范围')"
|
||||
:rules="[
|
||||
{ required: true, message: t('user.info.phone.required') },
|
||||
{ match: /^1[3-9]\d{9}$/, message: t('user.info.phone.format') },
|
||||
]"
|
||||
:validate-trigger="['change', 'input']"
|
||||
>
|
||||
<a-input v-model="formData.phone" :placeholder="$t('请选择范围')" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
field="password"
|
||||
:label="$t('发布时间')"
|
||||
:validate-trigger="['change', 'input']"
|
||||
:rules="[{ required: true, message: t('user.info.password.required') }]"
|
||||
>
|
||||
<!-- v-if="isCreate"-->
|
||||
<a-input
|
||||
v-model="formData.password"
|
||||
:placeholder="$t('请选择发布时间')"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item field="nickName" :label="$t('公告内容')">
|
||||
<a-textarea
|
||||
default-value="请输入内容"
|
||||
:auto-size="{
|
||||
minRows: 2,
|
||||
maxRows: 5,
|
||||
}"
|
||||
style="margin-top: 20px"
|
||||
v-model="formData.content"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import useVisible from '@/hooks/visible';
|
||||
import { computed, PropType, ref } from 'vue';
|
||||
import { CreateRecord } from '@/api/user';
|
||||
import { FormInstance } from '@arco-design/web-vue/es/form';
|
||||
import { deptList } from '@/api/dept';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { useUserStore } from '@/store';
|
||||
|
||||
const props = defineProps({
|
||||
prem: {
|
||||
type: Object as PropType<CreateRecord>,
|
||||
},
|
||||
isCreate: Boolean,
|
||||
});
|
||||
const { t } = useI18n();
|
||||
const modalTitle = computed(() => {
|
||||
return props.isCreate ? t('新增公告') : t('编辑公告');
|
||||
});
|
||||
const { visible, setVisible } = useVisible(false);
|
||||
const checkKeys = ref<number[]>([]);
|
||||
|
||||
const CreateRef = ref<FormInstance>();
|
||||
|
||||
const formData = ref<any>({});
|
||||
|
||||
let formDifer = {};
|
||||
const userStore = useUserStore();
|
||||
|
||||
// 部门数据
|
||||
const deptOptions = ref();
|
||||
const getDeptData = async () => {
|
||||
const res = await deptList();
|
||||
deptOptions.value = res.data.records;
|
||||
};
|
||||
// 角色数据
|
||||
// const roleOptions = ref();
|
||||
// const getRoleData = async () => {
|
||||
// const res = await queryRoleList('');
|
||||
// roleOptions.value = res.data.records.filter((item: any) => {
|
||||
// return item.enabled !== false;
|
||||
// });
|
||||
// };
|
||||
|
||||
// 组件被点击
|
||||
// const handleClick = () => {
|
||||
// getDeptData();
|
||||
// // getRoleData();
|
||||
// const userId = props.prem?.id;
|
||||
// // 编辑
|
||||
// if (!props.isCreate && userId) {
|
||||
// formData.value = props.prem;
|
||||
// formDifer = { ...props.prem };
|
||||
// }
|
||||
// setVisible(true);
|
||||
// };
|
||||
|
||||
// 做出只修改的部分
|
||||
const diffDataForm = (newData: any, oldData: any) => {
|
||||
const result = {}; // 报错修改的字段内容
|
||||
Object.keys(oldData).forEach((key) => {
|
||||
if (oldData[key] !== newData[key]) {
|
||||
result[key] = newData[key];
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
// 提交
|
||||
const handleSubmit = async () => {
|
||||
const valid = await CreateRef.value?.validate();
|
||||
if (!valid) {
|
||||
formData.value.permissionIds = checkKeys.value;
|
||||
// 新增
|
||||
if (props.isCreate) {
|
||||
// formData.value.username = formData.value.email;
|
||||
const res = await userStore.createUser(formData.value);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('create.sucess'),
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
}
|
||||
CreateRef.value?.resetFields();
|
||||
} else {
|
||||
// 编辑
|
||||
formDifer = diffDataForm(formData.value, formDifer);
|
||||
if (Object.keys(formDifer).length === 0) {
|
||||
Message.success({
|
||||
content: t('unmodified'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
} else {
|
||||
formDifer.id = formData.value.id;
|
||||
const res = await userStore.updateUser(formDifer);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('modify.sucess'),
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
checkKeys.value = [];
|
||||
setVisible(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭
|
||||
const handleCancel = async () => {
|
||||
checkKeys.value = [];
|
||||
setVisible(false);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
445
src/views/notification/noticeSet/index.vue
Normal file
445
src/views/notification/noticeSet/index.vue
Normal file
@ -0,0 +1,445 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<Breadcrumb :items="['系统管理', '公告设置']" />
|
||||
<a-card class="general-card" title=" ">
|
||||
<a-row>
|
||||
<a-col :flex="1">
|
||||
<a-form
|
||||
:model="formModel"
|
||||
:label-col-props="{ span: 6 }"
|
||||
:wrapper-col-props="{ span: 18 }"
|
||||
label-align="right"
|
||||
>
|
||||
<a-row :gutter="18">
|
||||
<a-col :span="9">
|
||||
<a-form-item field="title" :label="$t('标题')">
|
||||
<a-input
|
||||
v-model="formModel.title"
|
||||
style="width: 360px"
|
||||
:placeholder="$t('请输入标题')"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="9">
|
||||
<a-form-item field="enable" :label="$t('状态')">
|
||||
<a-select
|
||||
v-model="formModel.states"
|
||||
style="width: 360px"
|
||||
:placeholder="$t('请选择状态')"
|
||||
:options="statusOptions"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="9">
|
||||
<a-form-item field="publishTimeBegin" :label="$t('开始时间')">
|
||||
<a-date-picker
|
||||
v-model="formModel.publishTimeBegin"
|
||||
style="width: 360px"
|
||||
show-time
|
||||
:time-picker-props="{ defaultValue: '09:09:06' }"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
:allow-clear="false"
|
||||
@select="onSelect"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="9">
|
||||
<a-form-item field="publishTimeEnd" :label="$t('结束时间')">
|
||||
<a-date-picker
|
||||
v-model="formModel.publishTimeEnd"
|
||||
style="width: 360px"
|
||||
show-time
|
||||
:time-picker-props="{ defaultValue: '09:09:06' }"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
:allow-clear="false"
|
||||
@select="onSelect"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-col>
|
||||
<a-divider style="height: 84px" direction="vertical" />
|
||||
<a-col :flex="'86px'" style="text-align: right">
|
||||
<a-space direction="vertical" :size="18">
|
||||
<a-button type="primary" @click="search">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
查询
|
||||
</a-button>
|
||||
<a-button @click="reset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-divider style="margin-top: 0" />
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<a-space>
|
||||
<NoticeEdit
|
||||
ref="createUserRef"
|
||||
:is-create="true"
|
||||
@refresh="search"
|
||||
/>
|
||||
</a-space>
|
||||
<a-button style="margin-left: 20px" @click="generateExcel">
|
||||
<template #icon>
|
||||
<icon-download size="18" />
|
||||
</template>
|
||||
导出
|
||||
</a-button>
|
||||
</a-col>
|
||||
<a-col
|
||||
:span="12"
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
padding-bottom: 20px;
|
||||
"
|
||||
>
|
||||
<a-tooltip :content="$t('刷新')">
|
||||
<div class="action-icon" @click="search">
|
||||
<icon-refresh size="18" />
|
||||
</div>
|
||||
</a-tooltip>
|
||||
|
||||
<a-dropdown @select="handleSelectDensity">
|
||||
<a-tooltip :content="$t('密度')">
|
||||
<div class="action-icon"><icon-line-height size="18" /></div>
|
||||
</a-tooltip>
|
||||
<template #content>
|
||||
<a-doption
|
||||
v-for="item in densityList"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:class="{ active: item.value === sizeof }"
|
||||
>
|
||||
<span>{{ item.name }}</span>
|
||||
</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
|
||||
<a-tooltip :content="$t('列设置')">
|
||||
<a-popover
|
||||
trigger="click"
|
||||
position="bl"
|
||||
@popup-visible-change="popupVisibleChange"
|
||||
>
|
||||
<div class="action-icon"><icon-settings size="18" /></div>
|
||||
<template #content>
|
||||
<div id="tableSetting">
|
||||
<div
|
||||
v-for="(item, index) in showColumns"
|
||||
:key="item.dataIndex"
|
||||
class="setting"
|
||||
>
|
||||
<div style="margin-right: 4px; cursor: move">
|
||||
<icon-drag-arrow />
|
||||
</div>
|
||||
<div>
|
||||
<a-checkbox
|
||||
v-model="item.checked"
|
||||
@change="
|
||||
handleChange($event, item as TableColumnData, index)
|
||||
"
|
||||
>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
<div class="title">
|
||||
{{ item.title === '#' ? '序列号' : item.title }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-popover>
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-table
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:pagination="false"
|
||||
:columns="(cloneColumns as TableColumnData[])"
|
||||
:data="renderData"
|
||||
:bordered="false"
|
||||
:size="size"
|
||||
style="margin-bottom: 40px"
|
||||
:filter-icon-align-left="alignLeft"
|
||||
@change="handleSortChange"
|
||||
@page-change="onPageChange"
|
||||
>
|
||||
<template #index="{ rowIndex }">
|
||||
{{ rowIndex + 1 + (pagination.current - 1) * pagination.size }}
|
||||
</template>
|
||||
<template #enabled="{ record }">
|
||||
<a-switch
|
||||
:model-value="record.enabled"
|
||||
:checked-value="true"
|
||||
:unchecked-value="false"
|
||||
@change="enabledStatus(record)"
|
||||
/>
|
||||
</template>
|
||||
<template #operations="{ record }">
|
||||
<a-button
|
||||
type="outline"
|
||||
size="small"
|
||||
status="success"
|
||||
style="padding: 7px; margin-right: 10px"
|
||||
>
|
||||
<template #icon><icon-list /></template>
|
||||
详情
|
||||
</a-button>
|
||||
|
||||
<NoticeEdit
|
||||
ref="editUserRef"
|
||||
:prem="record"
|
||||
:is-create="false"
|
||||
@refresh="fetchData"
|
||||
/>
|
||||
<a-button
|
||||
type="outline"
|
||||
size="small"
|
||||
status="danger"
|
||||
style="padding: 7px"
|
||||
>
|
||||
<template #icon><icon-delete /></template>
|
||||
删除
|
||||
</a-button>
|
||||
</template>
|
||||
</a-table>
|
||||
<a-pagination
|
||||
style="float: right; position: relative; right: 1px; bottom: 25px"
|
||||
:total="pagination.total"
|
||||
:size="size"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
@page-size-change="onSizeChange"
|
||||
@change="onPageChange"
|
||||
/>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import { UserRecord, UserParams } from '@/api/user';
|
||||
import { Pagination } from '@/types/global';
|
||||
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
|
||||
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
|
||||
import { useUserStore } from '@/store';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import useTableOption from '@/hooks/table-option';
|
||||
import NoticeEdit from './components/notice-edit.vue';
|
||||
|
||||
const generateFormModel = () => {
|
||||
return {
|
||||
title: '',
|
||||
states: '',
|
||||
publishTimeBegin: '',
|
||||
publishTimeEnd: '',
|
||||
};
|
||||
};
|
||||
|
||||
const { loading, setLoading } = useLoading(true);
|
||||
const { t } = useI18n();
|
||||
const renderData = ref<UserRecord[]>([]);
|
||||
const formModel = ref(generateFormModel());
|
||||
|
||||
const {
|
||||
cloneColumns,
|
||||
showColumns,
|
||||
densityList,
|
||||
handleSelectDensity,
|
||||
handleChange,
|
||||
popupVisibleChange,
|
||||
deepClone,
|
||||
} = useTableOption();
|
||||
const sizeof = useTableOption().size;
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const pagination: Pagination = {
|
||||
page: 1,
|
||||
size: 10,
|
||||
current: 1,
|
||||
total: null,
|
||||
};
|
||||
|
||||
const columns = computed<TableColumnData[]>(() => [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
slotName: 'index',
|
||||
width: 60,
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
dataIndex: 'title',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('时间'),
|
||||
dataIndex: 'publishTimeBegin',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('状态'),
|
||||
dataIndex: 'states',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operations',
|
||||
slotName: 'operations',
|
||||
},
|
||||
]);
|
||||
const statusOptions = computed<SelectOptionData[]>(() => [
|
||||
{
|
||||
label: t('已发布'),
|
||||
value: 'true',
|
||||
},
|
||||
{
|
||||
label: t('未发布'),
|
||||
value: 'false',
|
||||
},
|
||||
]);
|
||||
|
||||
// 获取公告列表
|
||||
const fetchData = async (
|
||||
params: UserParams = { page: 1, size: 10, current: 1 }
|
||||
) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await userStore.getUserList(params);
|
||||
renderData.value = res.data.records;
|
||||
pagination.page = res.data.page;
|
||||
pagination.current = res.data.current;
|
||||
pagination.total = res.data.total;
|
||||
pagination.size = res.data.size;
|
||||
} catch (err) {
|
||||
// you can report use errorHandler or other
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 查询
|
||||
const search = () => {
|
||||
fetchData({
|
||||
...pagination,
|
||||
...formModel.value,
|
||||
} as unknown as UserParams);
|
||||
};
|
||||
|
||||
// 分页发生改变
|
||||
const onPageChange = (current: number) => {
|
||||
pagination.page = current;
|
||||
pagination.current = current;
|
||||
search();
|
||||
};
|
||||
|
||||
// 数据条数改变
|
||||
const onSizeChange = (size: number) => {
|
||||
pagination.size = size;
|
||||
search();
|
||||
};
|
||||
|
||||
search();
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
formModel.value = generateFormModel();
|
||||
};
|
||||
|
||||
// 表格内部排序
|
||||
const alignLeft = ref(false);
|
||||
const handleSortChange = (
|
||||
data: any,
|
||||
extra: any,
|
||||
currentDataSource: any
|
||||
) => {};
|
||||
|
||||
// 是否启用
|
||||
const enabledStatus = async (record: string) => {
|
||||
record.enabled = !record.enabled;
|
||||
const res = await userStore.enabledUser(record.id);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('modify.status.sucess'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
} else {
|
||||
Message.error({
|
||||
content: t('modify.status.fail'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 删除
|
||||
// const handleDelete = async (record: UserRecord) => {
|
||||
// const res = await userStore.removeUser(record.id);
|
||||
// if (res.status === 200) {
|
||||
// Message.success({
|
||||
// content: '删除成功',
|
||||
// duration: 5 * 1000,
|
||||
// });
|
||||
// search();
|
||||
// }
|
||||
// };
|
||||
|
||||
watch(() => columns.value, deepClone, { deep: true, immediate: true });
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.container {
|
||||
padding: 0 20px 20px 20px;
|
||||
}
|
||||
|
||||
:deep(.arco-table-th) {
|
||||
&:last-child {
|
||||
.arco-table-th-item-title {
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
margin-left: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: #0960bd;
|
||||
background-color: #e3f4fc;
|
||||
}
|
||||
|
||||
.setting {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 200px;
|
||||
|
||||
.title {
|
||||
margin-left: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,51 +1,48 @@
|
||||
<template>
|
||||
<a-button v-if="props.isCreate" type="primary" @click="handleClick">
|
||||
<template #icon><icon-plus /></template>
|
||||
新建
|
||||
</a-button>
|
||||
<a-button
|
||||
v-if="!props.isCreate"
|
||||
type="outline"
|
||||
size="small"
|
||||
:style="{ marginRight: '10px', padding: '7px' }"
|
||||
@click="handleClick"
|
||||
>
|
||||
<template #icon><icon-edit /></template>
|
||||
修改
|
||||
</a-button>
|
||||
<a-modal
|
||||
width="700px"
|
||||
:visible="visible"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<template #title>{{ modalTitle }}</template>
|
||||
<a-form ref="createEditRef" :model="formData" :style="{ width: '650px' }">
|
||||
<a-form-item
|
||||
field="name"
|
||||
label="权限名称"
|
||||
:validate-trigger="['change', 'input']"
|
||||
:rules="[{ required: true, message: t('auth.info.name.required') }]"
|
||||
>
|
||||
<a-input
|
||||
v-model="formData.name"
|
||||
placeholder="请输入权限名称"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-button v-if="props.isCreate" type="primary" @click="handleClick">
|
||||
<template #icon><icon-plus /></template>
|
||||
新建
|
||||
</a-button>
|
||||
<a-button
|
||||
v-if="!props.isCreate"
|
||||
type="outline"
|
||||
size="small"
|
||||
:style="{ marginRight: '10px', padding: '7px' }"
|
||||
@click="handleClick"
|
||||
>
|
||||
<template #icon><icon-edit /></template>
|
||||
修改
|
||||
</a-button>
|
||||
<a-modal
|
||||
width="700px"
|
||||
:visible="visible"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<template #title>{{ modalTitle }}</template>
|
||||
<a-form ref="createEditRef" :model="formData" :style="{ width: '650px' }">
|
||||
<a-form-item
|
||||
field="name"
|
||||
label="权限名称"
|
||||
:validate-trigger="['change', 'input']"
|
||||
:rules="[{ required: true, message: t('auth.info.name.required') }]"
|
||||
>
|
||||
<a-input v-model="formData.name" placeholder="请输入权限名称" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item field="remark" label="备注">
|
||||
<a-textarea
|
||||
v-model="formData.remark"
|
||||
:show-word-limit="true"
|
||||
placeholder="请输入备注"
|
||||
style="height: 100px"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
<a-form-item field="remark" label="备注">
|
||||
<a-textarea
|
||||
v-model="formData.remark"
|
||||
:show-word-limit="true"
|
||||
placeholder="请输入备注"
|
||||
style="height: 100px"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import useVisible from '@/hooks/visible';
|
||||
import { computed, PropType, ref } from 'vue';
|
||||
@ -62,7 +59,7 @@
|
||||
});
|
||||
const { t } = useI18n();
|
||||
const modalTitle = computed(() => {
|
||||
return props.isCreate ? '创建权限' : '编辑权限';
|
||||
return props.isCreate ? t('Create Auth Info') : t('Edit Auth Info');
|
||||
});
|
||||
const { visible, setVisible } = useVisible(false);
|
||||
const createEditRef = ref<FormInstance>();
|
||||
@ -86,7 +83,7 @@
|
||||
if (!props.isCreate && authId) {
|
||||
authStore
|
||||
.getAuthDetail(authId)
|
||||
.then((res:any) => {
|
||||
.then((res: any) => {
|
||||
formData.value = res.data;
|
||||
})
|
||||
.then(() => {
|
||||
@ -131,7 +128,6 @@
|
||||
createEditRef.value?.resetFields();
|
||||
setVisible(false);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
@ -1,133 +1,158 @@
|
||||
<template>
|
||||
<a-table row-key="id" :loading="loading" :pagination="false" :columns="columns" :data="data" :bordered="false"
|
||||
:size="size" style="margin-bottom: 40px" @pageChange="onPageChange">
|
||||
<template #index="{ rowIndex }">
|
||||
{{ rowIndex + 1 }}
|
||||
</template>
|
||||
<template #createTime="{ record }">
|
||||
{{ dayjs(record.createTime).format('YYYY-MM-DD') }}
|
||||
</template>
|
||||
<template #enabled="{ record }">
|
||||
<a-switch :model-value="record.enabled" :checked-value="true" :unchecked-value="false"
|
||||
@change="enabledStatus(record)" />
|
||||
</template>
|
||||
<template #operations="{ record }">
|
||||
<!-- 编辑 -->
|
||||
<AuthEdit ref="editRef" :prem="record" :is-create="false" @refresh="fetchData" />
|
||||
<a-popconfirm :content="t('Confirm the deletion of this role')" type="error" @ok="handleDelete(record)">
|
||||
<a-button type="outline" size="small" status="danger" style="padding: 7px">
|
||||
<template #icon><icon-delete /></template>
|
||||
删除
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</a-table>
|
||||
<a-table
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:pagination="false"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:bordered="false"
|
||||
:size="size"
|
||||
style="margin-bottom: 40px"
|
||||
@pageChange="onPageChange"
|
||||
>
|
||||
<template #index="{ rowIndex }">
|
||||
{{ rowIndex + 1 }}
|
||||
</template>
|
||||
<template #createTime="{ record }">
|
||||
{{ dayjs(record.createTime).format('YYYY-MM-DD') }}
|
||||
</template>
|
||||
<template #enabled="{ record }">
|
||||
<a-switch
|
||||
:model-value="record.enabled"
|
||||
:checked-value="true"
|
||||
:unchecked-value="false"
|
||||
@change="enabledStatus(record)"
|
||||
/>
|
||||
</template>
|
||||
<template #operations="{ record }">
|
||||
<!-- 编辑 -->
|
||||
<AuthEdit
|
||||
ref="editRef"
|
||||
:prem="record"
|
||||
:is-create="false"
|
||||
@refresh="fetchData"
|
||||
/>
|
||||
<a-popconfirm
|
||||
:content="t('Confirm the deletion of this role')"
|
||||
type="error"
|
||||
@ok="handleDelete(record)"
|
||||
>
|
||||
<a-button
|
||||
type="outline"
|
||||
size="small"
|
||||
status="danger"
|
||||
style="padding: 7px"
|
||||
>
|
||||
<template #icon><icon-delete /></template>
|
||||
删除
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, defineEmits} from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { useAuthStore } from '@/store';
|
||||
import { AuthRecord } from '@/api/authority';
|
||||
// import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
|
||||
import AuthEdit from './auth-edit.vue';
|
||||
import { defineProps, defineEmits } from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { useAuthStore } from '@/store';
|
||||
import { AuthRecord } from '@/api/authority';
|
||||
// import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
|
||||
import AuthEdit from './auth-edit.vue';
|
||||
|
||||
|
||||
const authStore = useAuthStore();
|
||||
const props = defineProps({
|
||||
const authStore = useAuthStore();
|
||||
const props = defineProps({
|
||||
loading: Boolean,
|
||||
data: Array,
|
||||
size: String,
|
||||
});
|
||||
});
|
||||
|
||||
const { t } = useI18n();
|
||||
const emit = defineEmits(['pageChange', 'refresh','search']);
|
||||
// 表格头部
|
||||
// const columns = computed<TableColumnData[]>(() => [
|
||||
// {
|
||||
// title: t('roleTable.columns.index'),
|
||||
// dataIndex: 'index',
|
||||
// slotName: 'index',
|
||||
// },
|
||||
// {
|
||||
// title: t('roleTable.columns.name'),
|
||||
// dataIndex: 'name',
|
||||
// sortable: {
|
||||
// sortDirections: ['ascend', 'descend'],
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// title: t('roleTable.columns.remark'),
|
||||
// dataIndex: 'remark',
|
||||
// },
|
||||
// {
|
||||
// title: t('roleTable.columns.createTime'),
|
||||
// dataIndex: 'createTime',
|
||||
// slotName: 'createTime',
|
||||
// sortable: {
|
||||
// sortDirections: ['ascend', 'descend'],
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// title: t('roleTable.columns.enabled'),
|
||||
// dataIndex: 'enabled',
|
||||
// slotName: 'enabled',
|
||||
// },
|
||||
// {
|
||||
// title: t('searchTable.columns.operations'),
|
||||
// dataIndex: 'operations',
|
||||
// slotName: 'operations',
|
||||
// },
|
||||
// ]);
|
||||
const { t } = useI18n();
|
||||
const emit = defineEmits(['pageChange', 'refresh', 'search']);
|
||||
// 表格头部
|
||||
// const columns = computed<TableColumnData[]>(() => [
|
||||
// {
|
||||
// title: t('roleTable.columns.index'),
|
||||
// dataIndex: 'index',
|
||||
// slotName: 'index',
|
||||
// },
|
||||
// {
|
||||
// title: t('roleTable.columns.name'),
|
||||
// dataIndex: 'name',
|
||||
// sortable: {
|
||||
// sortDirections: ['ascend', 'descend'],
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// title: t('roleTable.columns.remark'),
|
||||
// dataIndex: 'remark',
|
||||
// },
|
||||
// {
|
||||
// title: t('roleTable.columns.createTime'),
|
||||
// dataIndex: 'createTime',
|
||||
// slotName: 'createTime',
|
||||
// sortable: {
|
||||
// sortDirections: ['ascend', 'descend'],
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// title: t('roleTable.columns.enabled'),
|
||||
// dataIndex: 'enabled',
|
||||
// slotName: 'enabled',
|
||||
// },
|
||||
// {
|
||||
// title: t('searchTable.columns.operations'),
|
||||
// dataIndex: 'operations',
|
||||
// slotName: 'operations',
|
||||
// },
|
||||
// ]);
|
||||
|
||||
|
||||
const fetchData = () => {
|
||||
const fetchData = () => {
|
||||
emit('refresh');
|
||||
};
|
||||
// 分页
|
||||
const onPageChange = (page: number) => {
|
||||
};
|
||||
// 分页
|
||||
const onPageChange = (page: number) => {
|
||||
emit('pageChange', page);
|
||||
};
|
||||
};
|
||||
|
||||
// 是否启用
|
||||
const enabledStatus = async (record: string) => {
|
||||
record.enabled = !record.enabled;
|
||||
const res = await authStore.enabledAuth(record.id);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('modify.status.sucess'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
} else {
|
||||
Message.error({
|
||||
content: t('modify.status.fail'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
}
|
||||
};
|
||||
// 是否启用
|
||||
const enabledStatus = async (record: string) => {
|
||||
record.enabled = !record.enabled;
|
||||
const res = await authStore.enabledAuth(record.id);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('modify.status.sucess'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
} else {
|
||||
Message.error({
|
||||
content: t('modify.status.fail'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 删除
|
||||
const handleDelete = async (record: AuthRecord) => {
|
||||
const res = await authStore.removeAuth(record.id);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('delete.auth.sucess'),
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
emit('search');
|
||||
} else {
|
||||
Message.error({
|
||||
content: t('delete.auth.fail'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
}
|
||||
};
|
||||
// 删除
|
||||
const handleDelete = async (record: AuthRecord) => {
|
||||
const res = await authStore.removeAuth(record.id);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('delete.auth.sucess'),
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
emit('search');
|
||||
} else {
|
||||
Message.error({
|
||||
content: t('delete.auth.fail'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// watch(() => columns.value, deepClone, { deep: true, immediate: true });
|
||||
// watch(() => columns.value, deepClone, { deep: true, immediate: true });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 添加一些样式 */
|
||||
/* 添加一些样式 */
|
||||
</style>
|
158
src/views/system/role/components/role-table.vue
Normal file
158
src/views/system/role/components/role-table.vue
Normal file
@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<a-table
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:pagination="false"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:bordered="false"
|
||||
:size="size"
|
||||
style="margin-bottom: 40px"
|
||||
@pageChange="onPageChange"
|
||||
>
|
||||
<template #index="{ rowIndex }">
|
||||
{{ rowIndex + 1 }}
|
||||
</template>
|
||||
<template #createTime="{ record }">
|
||||
{{ dayjs(record.createTime).format('YYYY-MM-DD') }}
|
||||
</template>
|
||||
<template #enabled="{ record }">
|
||||
<a-switch
|
||||
:model-value="record.enabled"
|
||||
:checked-value="true"
|
||||
:unchecked-value="false"
|
||||
@change="enabledStatus(record)"
|
||||
/>
|
||||
</template>
|
||||
<template #operations="{ record }">
|
||||
<!-- 编辑 -->
|
||||
<RoleEdit
|
||||
ref="editRef"
|
||||
:prem="record"
|
||||
:is-create="false"
|
||||
@refresh="fetchData"
|
||||
/>
|
||||
<a-popconfirm
|
||||
:content="t('Confirm the deletion of this role')"
|
||||
type="error"
|
||||
@ok="handleDelete(record)"
|
||||
>
|
||||
<a-button
|
||||
type="outline"
|
||||
size="small"
|
||||
status="danger"
|
||||
style="padding: 7px"
|
||||
>
|
||||
<template #icon><icon-delete /></template>
|
||||
删除
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, defineEmits } from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { useRoleStore } from '@/store';
|
||||
import { RoleRecord } from '@/api/role';
|
||||
// import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
|
||||
import RoleEdit from './role-edit.vue';
|
||||
|
||||
const roleStore = useRoleStore();
|
||||
const props = defineProps({
|
||||
loading: Boolean,
|
||||
data: Array,
|
||||
size: String,
|
||||
});
|
||||
|
||||
const { t } = useI18n();
|
||||
const emit = defineEmits(['pageChange', 'refresh', 'search']);
|
||||
// 表格头部
|
||||
// const columns = computed<TableColumnData[]>(() => [
|
||||
// {
|
||||
// title: t('roleTable.columns.index'),
|
||||
// dataIndex: 'index',
|
||||
// slotName: 'index',
|
||||
// },
|
||||
// {
|
||||
// title: t('roleTable.columns.name'),
|
||||
// dataIndex: 'name',
|
||||
// sortable: {
|
||||
// sortDirections: ['ascend', 'descend'],
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// title: t('roleTable.columns.remark'),
|
||||
// dataIndex: 'remark',
|
||||
// },
|
||||
// {
|
||||
// title: t('roleTable.columns.createTime'),
|
||||
// dataIndex: 'createTime',
|
||||
// slotName: 'createTime',
|
||||
// sortable: {
|
||||
// sortDirections: ['ascend', 'descend'],
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// title: t('roleTable.columns.enabled'),
|
||||
// dataIndex: 'enabled',
|
||||
// slotName: 'enabled',
|
||||
// },
|
||||
// {
|
||||
// title: t('searchTable.columns.operations'),
|
||||
// dataIndex: 'operations',
|
||||
// slotName: 'operations',
|
||||
// },
|
||||
// ]);
|
||||
|
||||
const fetchData = () => {
|
||||
emit('refresh');
|
||||
};
|
||||
// 分页
|
||||
const onPageChange = (page: number) => {
|
||||
emit('pageChange', page);
|
||||
};
|
||||
|
||||
// 是否启用
|
||||
const enabledStatus = async (record: string) => {
|
||||
record.enabled = !record.enabled;
|
||||
const res = await roleStore.enabledRole(record.id);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('modify.status.sucess'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
} else {
|
||||
Message.error({
|
||||
content: t('modify.status.fail'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 删除
|
||||
const handleDelete = async (record: RoleRecord) => {
|
||||
const res = await roleStore.removeRole(record.id);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('delete.role.sucess'),
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
emit('search');
|
||||
} else {
|
||||
Message.error({
|
||||
content: t('delete.role.fail'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// watch(() => columns.value, deepClone, { deep: true, immediate: true });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 添加一些样式 */
|
||||
</style>
|
@ -43,13 +43,13 @@
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入昵称',
|
||||
message: $t('userSetting.form.error.nickname.required'),
|
||||
},
|
||||
]"
|
||||
>
|
||||
<a-input
|
||||
v-model="formData.nickName"
|
||||
placeholder='请输入昵称'
|
||||
:placeholder="$t('userSetting.basicInfo.placeholder.nickname')"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
@ -79,42 +79,42 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { useUserStore } from '@/store';
|
||||
import { FormInstance } from '@arco-design/web-vue/es/form';
|
||||
import { UserState } from '@/store/modules/user/types';
|
||||
import { selfUpdate, getUserInfo } from '@/api/user';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { ref } from 'vue';
|
||||
import { useUserStore } from '@/store';
|
||||
import { FormInstance } from '@arco-design/web-vue/es/form';
|
||||
import { UserState } from '@/store/modules/user/types';
|
||||
import { selfUpdate, getUserInfo } from '@/api/user';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const formData = ref<UserState>({
|
||||
...userStore.userInfo,
|
||||
});
|
||||
const validate = async () => {
|
||||
const valid = await formRef.value?.validate();
|
||||
if (!valid) {
|
||||
// do some thing
|
||||
// you also can use html-type to submit
|
||||
const res = await selfUpdate(formData.value);
|
||||
if (res.status === 200) {
|
||||
await userStore.info();
|
||||
Message.success({
|
||||
content: '编辑成功',
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
const formRef = ref<FormInstance>();
|
||||
const formData = ref<UserState>({
|
||||
...userStore.userInfo,
|
||||
});
|
||||
const validate = async () => {
|
||||
const valid = await formRef.value?.validate();
|
||||
if (!valid) {
|
||||
// do some thing
|
||||
// you also can use html-type to submit
|
||||
const res = await selfUpdate(formData.value);
|
||||
if (res.status === 200) {
|
||||
await userStore.info();
|
||||
Message.success({
|
||||
content: '编辑成功',
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const reset = async () => {
|
||||
await formRef.value?.resetFields();
|
||||
};
|
||||
};
|
||||
const reset = async () => {
|
||||
await formRef.value?.resetFields();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.form {
|
||||
width: 540px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
.form {
|
||||
width: 540px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
</style>
|
||||
|
@ -50,60 +50,57 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { FormInstance } from '@arco-design/web-vue/es/form';
|
||||
import { PasswordReSetModel, resetPassword } from '@/api/user';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import useUser from '@/hooks/user';
|
||||
import router from '@/router';
|
||||
import { clearToken } from '@/utils/auth';
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { FormInstance } from '@arco-design/web-vue/es/form';
|
||||
import { PasswordReSetModel, resetPassword } from '@/api/user';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import router from '@/router';
|
||||
import { clearToken } from '@/utils/auth';
|
||||
|
||||
const { t } = useI18n();
|
||||
const { t } = useI18n();
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const formData = ref<PasswordReSetModel>({
|
||||
oldPassword: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
});
|
||||
const checkEquals = (
|
||||
value: string | undefined,
|
||||
callback: (error?: string) => void
|
||||
) => {
|
||||
if (!value) {
|
||||
callback(t('userSetting.passwordReset.form.validate.blank'));
|
||||
} else if (formData.value.password !== formData.value.confirmPassword) {
|
||||
callback(t('userSetting.passwordReset.form.validate.noEquals'));
|
||||
}
|
||||
};
|
||||
|
||||
const user = useUser();
|
||||
|
||||
const validate = async () => {
|
||||
const vali = await formRef.value?.validate();
|
||||
if (!vali) {
|
||||
const res = await resetPassword(formData.value);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('passwordReset.sucess'),
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
clearToken();
|
||||
router.push({
|
||||
name: 'login',
|
||||
});
|
||||
const formRef = ref<FormInstance>();
|
||||
const formData = ref<PasswordReSetModel>({
|
||||
oldPassword: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
});
|
||||
const checkEquals = (
|
||||
value: string | undefined,
|
||||
callback: (error?: string) => void
|
||||
) => {
|
||||
if (!value) {
|
||||
callback(t('userSetting.passwordReset.form.validate.blank'));
|
||||
} else if (formData.value.password !== formData.value.confirmPassword) {
|
||||
callback(t('userSetting.passwordReset.form.validate.noEquals'));
|
||||
}
|
||||
}
|
||||
};
|
||||
const reset = async () => {
|
||||
await formRef.value?.resetFields();
|
||||
};
|
||||
};
|
||||
|
||||
const validate = async () => {
|
||||
const vali = await formRef.value?.validate();
|
||||
if (!vali) {
|
||||
const res = await resetPassword(formData.value);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('passwordReset.sucess'),
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
clearToken();
|
||||
router.push({
|
||||
name: 'login',
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
const reset = async () => {
|
||||
await formRef.value?.resetFields();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.form {
|
||||
width: 540px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
.form {
|
||||
width: 540px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
</style>
|
||||
|
@ -2,12 +2,12 @@
|
||||
<a-card :bordered="false">
|
||||
<a-space :size="54">
|
||||
<a-upload
|
||||
:custom-request="Onchange"
|
||||
:custom-request="() => {}"
|
||||
list-type="picture-card"
|
||||
:file-list="fileList"
|
||||
:show-upload-button="true"
|
||||
:show-file-list="false"
|
||||
@change="Onchange"
|
||||
@change="() => {}"
|
||||
>
|
||||
<template #upload-button>
|
||||
<a-avatar :size="100" class="info-avatar">
|
||||
@ -46,66 +46,81 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { ref } from 'vue';
|
||||
import type { FileItem } from '@arco-design/web-vue/es/upload/interfaces';
|
||||
import { useUserStore} from '@/store';
|
||||
import userIcon from '@/assets/images/user-circle.png';
|
||||
import type { DescData } from '@arco-design/web-vue/es/descriptions/interface';
|
||||
import dayjs from 'dayjs';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { selfUpdate } from '@/api/user';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { ref } from 'vue';
|
||||
import type { FileItem } from '@arco-design/web-vue/es/upload/interfaces';
|
||||
import { useUserStore } from '@/store';
|
||||
import userIcon from '@/assets/images/user-circle.png';
|
||||
import type { DescData } from '@arco-design/web-vue/es/descriptions/interface';
|
||||
import dayjs from 'dayjs';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { selfUpdate } from '@/api/user';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const { t } = useI18n();
|
||||
// const ticketStore = useTicketStore();
|
||||
const userStore = useUserStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
const file = {
|
||||
uid: '-2',
|
||||
name: 'avatar.png',
|
||||
url: userStore.avatar ? userStore.avatar : userIcon,
|
||||
};
|
||||
const renderData = [
|
||||
{
|
||||
label: 'userSetting.label.name',
|
||||
value: userStore.username,
|
||||
},
|
||||
{
|
||||
label: 'userSetting.label.accountId',
|
||||
value: userStore.id,
|
||||
},
|
||||
{
|
||||
label: 'userSetting.label.phone',
|
||||
value: userStore.phone,
|
||||
},
|
||||
{
|
||||
label: 'userSetting.label.registrationDate',
|
||||
value: dayjs(userStore.createAt).format('YYYY-MM-DD hh:mm:ss'),
|
||||
},
|
||||
] as DescData[];
|
||||
const file = {
|
||||
uid: '-2',
|
||||
name: 'avatar.png',
|
||||
url: userStore.avatar ? userStore.avatar : userIcon,
|
||||
};
|
||||
const renderData = [
|
||||
{
|
||||
label: 'userSetting.label.name',
|
||||
value: userStore.username,
|
||||
},
|
||||
{
|
||||
label: 'userSetting.label.accountId',
|
||||
value: userStore.id,
|
||||
},
|
||||
{
|
||||
label: 'userSetting.label.phone',
|
||||
value: userStore.phone,
|
||||
},
|
||||
{
|
||||
label: 'userSetting.label.registrationDate',
|
||||
value: dayjs(userStore.createAt).format('YYYY-MM-DD hh:mm:ss'),
|
||||
},
|
||||
] as DescData[];
|
||||
|
||||
const fileList = ref<FileItem[]>([file]);
|
||||
const fileList = ref<FileItem[]>([file]);
|
||||
|
||||
const Onchange = async (option: any) => {
|
||||
const FormDatas = new FormData();
|
||||
FormDatas.append('file', option.fileItem.file);
|
||||
};
|
||||
// const Onchange = async (option: any) => {
|
||||
// const FormDatas = new FormData();
|
||||
// FormDatas.append('file', option.fileItem.file);
|
||||
// const res = await ticketStore.uploadFile(FormDatas);
|
||||
// if (res.status === 200) {
|
||||
// Message.success({
|
||||
// content: t('upload.sucess'),
|
||||
// duration: 3 * 1000,
|
||||
// });
|
||||
// res.data.name = res.data.fileName;
|
||||
// fileList.value.push(res.data);
|
||||
// await selfUpdate({ avatar: res.data.id });
|
||||
// await userStore.info();
|
||||
// } else {
|
||||
// Message.error({
|
||||
// content: t('upload.fail'),
|
||||
// duration: 3 * 1000,
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.arco-card {
|
||||
padding: 14px 0 4px 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
:deep(.arco-avatar-trigger-icon-button) {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
background-color: #e8f3ff;
|
||||
.arco-icon-camera {
|
||||
margin-top: 8px;
|
||||
color: rgb(var(--arcoblue-6));
|
||||
font-size: 14px;
|
||||
.arco-card {
|
||||
padding: 14px 0 4px 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
:deep(.arco-avatar-trigger-icon-button) {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
background-color: #e8f3ff;
|
||||
.arco-icon-camera {
|
||||
margin-top: 8px;
|
||||
color: rgb(var(--arcoblue-6));
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user