feat: platform 接入天梯登陆的 依赖
This commit is contained in:
parent
dd69823a00
commit
47c9ec1aba
@ -54,7 +54,8 @@
|
|||||||
"vue-types": "~5.1.3",
|
"vue-types": "~5.1.3",
|
||||||
"vue-virtual-scroller": "2.0.0-beta.8",
|
"vue-virtual-scroller": "2.0.0-beta.8",
|
||||||
"wujie": "^1.0.25",
|
"wujie": "^1.0.25",
|
||||||
"xlsx": "~0.18.5"
|
"xlsx": "~0.18.5",
|
||||||
|
"@sy/unified-login": "1.0.29"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "~19.5.0",
|
"@commitlint/cli": "~19.5.0",
|
||||||
|
@ -1,41 +1,30 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useUserStore } from '@/store/modules/user';
|
// import { useUserStore } from '@/store/modules/user';
|
||||||
import router from '@/router';
|
// import router from '@/router';
|
||||||
|
import appClient from '@/io/tianti';
|
||||||
|
|
||||||
|
console.log('appClient', appClient);
|
||||||
|
|
||||||
|
// axios拦截器
|
||||||
|
const { reqInterceptor, resInterceptor } = appClient.getInterceptor();
|
||||||
|
console.log('reqInterceptor', reqInterceptor);
|
||||||
|
console.log('resInterceptor', resInterceptor);
|
||||||
|
|
||||||
const baseApiUrl = import.meta.env.VITE_BASE_API_URL;
|
const baseApiUrl = import.meta.env.VITE_BASE_API_URL;
|
||||||
|
|
||||||
// 创建独立实例
|
// 创建独立实例
|
||||||
const instance = axios.create({
|
const instance = axios.create({
|
||||||
baseURL: baseApiUrl, // 基础URL直接放在实例配置中
|
baseURL: baseApiUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 请求拦截器改为使用实例
|
|
||||||
instance.interceptors.request.use(
|
instance.interceptors.request.use(
|
||||||
(config) => {
|
(config) => config,
|
||||||
// 可在此处添加统一请求头等配置
|
(error) => Promise.reject(error),
|
||||||
return config;
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
return Promise.reject(error);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
instance.interceptors.request.use(reqInterceptor.fulfilled, reqInterceptor.rejected);
|
||||||
|
|
||||||
// 响应拦截器改为使用实例
|
// 响应拦截器
|
||||||
instance.interceptors.response.use(
|
instance.interceptors.response.use(resInterceptor.fulfilled, resInterceptor.rejected);
|
||||||
(response) => {
|
|
||||||
// 如果响应数据中 code 为 -1,清空登录状态并跳转到登录页
|
|
||||||
if (response?.data?.code === -1) {
|
|
||||||
const userStore = useUserStore();
|
|
||||||
userStore.clearLoginStatus(); // 清空用户信息
|
|
||||||
router.push('/login'); // 直接使用路由实例
|
|
||||||
console.error('请求失败:', response.data.msg);
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
return Promise.reject(error);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// 导出实例
|
// 导出实例
|
||||||
export default instance;
|
export default instance;
|
||||||
|
12
apps/platform/src/io/tianti.ts
Normal file
12
apps/platform/src/io/tianti.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// @ts-ignore
|
||||||
|
import AxiosAppClient from '@sy/unified-login/es/app-client/axios';
|
||||||
|
|
||||||
|
export type Env = 'dev' | 'test' | 'pre' | 'prod';
|
||||||
|
|
||||||
|
const appClient = new AxiosAppClient({
|
||||||
|
appKey: 'y-code', // 应用标识,不同项目不能一样
|
||||||
|
env: 'prod', // dev:本地开发;test:测试;pre:预发布;prod:正式
|
||||||
|
devBaseUrl: `https://localhost:${import.meta.env.VITE_PORT}`, // 应用开发环境地址
|
||||||
|
});
|
||||||
|
|
||||||
|
export default appClient;
|
@ -33,10 +33,15 @@
|
|||||||
</Menu.Item> -->
|
</Menu.Item> -->
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
<Menu.Item>
|
<Menu.Item>
|
||||||
<div @click.prevent="doLogout">
|
<div @click.prevent="tianti.logout">
|
||||||
<poweroff-outlined /> {{ $t('layout.header.dropdownItemLoginOut') }}
|
<poweroff-outlined /> {{ $t('layout.header.dropdownItemLoginOut') }}
|
||||||
</div>
|
</div>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
<Menu.Item v-if="isDevEnv">
|
||||||
|
<div @click.prevent="tianti.openDev">
|
||||||
|
{{ $t('layout.header.openDev') }}
|
||||||
|
</div>
|
||||||
|
</Menu.Item>
|
||||||
</Menu>
|
</Menu>
|
||||||
</template>
|
</template>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
@ -49,6 +54,8 @@
|
|||||||
<script lang="tsx" setup>
|
<script lang="tsx" setup>
|
||||||
import { computed, type CSSProperties } from 'vue';
|
import { computed, type CSSProperties } from 'vue';
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
import { useRouter, useRoute } from 'vue-router';
|
||||||
|
import tianti from '@/io/tianti';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
QuestionCircleOutlined,
|
QuestionCircleOutlined,
|
||||||
MenuFoldOutlined,
|
MenuFoldOutlined,
|
||||||
@ -71,6 +78,8 @@
|
|||||||
import { LOGIN_NAME } from '@/router/constant';
|
import { LOGIN_NAME } from '@/router/constant';
|
||||||
import { useLayoutSettingStore } from '@/store/modules/layoutSetting';
|
import { useLayoutSettingStore } from '@/store/modules/layoutSetting';
|
||||||
|
|
||||||
|
const isDevEnv = import.meta.env.VITE_NODE_ENV === 'development';
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
collapsed: {
|
collapsed: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
{
|
{
|
||||||
"footer": { "onlinePreview": "在线预览", "onlineDocument": "在线文档" },
|
"footer": {
|
||||||
|
"onlinePreview": "在线预览",
|
||||||
|
"onlineDocument": "在线文档"
|
||||||
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"dropdownItemDoc": "文档",
|
"dropdownItemDoc": "文档",
|
||||||
"dropdownItemLoginOut": "退出系统",
|
"dropdownItemLoginOut": "退出系统",
|
||||||
|
"openDev": "打开开发环境",
|
||||||
"tooltipErrorLog": "错误日志",
|
"tooltipErrorLog": "错误日志",
|
||||||
"tooltipLock": "锁定屏幕",
|
"tooltipLock": "锁定屏幕",
|
||||||
"tooltipNotify": "消息通知",
|
"tooltipNotify": "消息通知",
|
||||||
|
|
||||||
"tooltipEntryFull": "全屏",
|
"tooltipEntryFull": "全屏",
|
||||||
"tooltipExitFull": "退出全屏",
|
"tooltipExitFull": "退出全屏",
|
||||||
|
|
||||||
"lockScreenPassword": "锁屏密码",
|
"lockScreenPassword": "锁屏密码",
|
||||||
"lockScreen": "锁定屏幕",
|
"lockScreen": "锁定屏幕",
|
||||||
"lockScreenBtn": "锁定",
|
"lockScreenBtn": "锁定",
|
||||||
|
|
||||||
"home": "首页"
|
"home": "首页"
|
||||||
},
|
},
|
||||||
"multipleTab": {
|
"multipleTab": {
|
||||||
@ -38,20 +38,15 @@
|
|||||||
"menuTypeMixSidebar": "左侧菜单混合模式",
|
"menuTypeMixSidebar": "左侧菜单混合模式",
|
||||||
"menuTypeMix": "顶部菜单混合模式",
|
"menuTypeMix": "顶部菜单混合模式",
|
||||||
"menuTypeTopMenu": "顶部菜单模式",
|
"menuTypeTopMenu": "顶部菜单模式",
|
||||||
|
|
||||||
"on": "开",
|
"on": "开",
|
||||||
"off": "关",
|
"off": "关",
|
||||||
"minute": "分钟",
|
"minute": "分钟",
|
||||||
|
|
||||||
"operatingTitle": "操作成功",
|
"operatingTitle": "操作成功",
|
||||||
"operatingContent": "复制成功,请到 src/settings/projectSetting.ts 中修改配置!",
|
"operatingContent": "复制成功,请到 src/settings/projectSetting.ts 中修改配置!",
|
||||||
"resetSuccess": "重置成功!",
|
"resetSuccess": "重置成功!",
|
||||||
|
|
||||||
"copyBtn": "拷贝",
|
"copyBtn": "拷贝",
|
||||||
"clearBtn": "清空缓存并返回登录页",
|
"clearBtn": "清空缓存并返回登录页",
|
||||||
|
|
||||||
"drawerTitle": "项目配置",
|
"drawerTitle": "项目配置",
|
||||||
|
|
||||||
"darkMode": "主题",
|
"darkMode": "主题",
|
||||||
"navMode": "导航栏模式",
|
"navMode": "导航栏模式",
|
||||||
"interfaceFunction": "界面功能",
|
"interfaceFunction": "界面功能",
|
||||||
@ -59,11 +54,9 @@
|
|||||||
"animation": "动画",
|
"animation": "动画",
|
||||||
"splitMenu": "分割菜单",
|
"splitMenu": "分割菜单",
|
||||||
"closeMixSidebarOnChange": "切换页面关闭菜单",
|
"closeMixSidebarOnChange": "切换页面关闭菜单",
|
||||||
|
|
||||||
"sysTheme": "系统主题",
|
"sysTheme": "系统主题",
|
||||||
"headerTheme": "顶栏主题",
|
"headerTheme": "顶栏主题",
|
||||||
"sidebarTheme": "菜单主题",
|
"sidebarTheme": "菜单主题",
|
||||||
|
|
||||||
"menuDrag": "侧边菜单拖拽",
|
"menuDrag": "侧边菜单拖拽",
|
||||||
"menuSearch": "菜单搜索",
|
"menuSearch": "菜单搜索",
|
||||||
"menuAccordion": "侧边菜单手风琴模式",
|
"menuAccordion": "侧边菜单手风琴模式",
|
||||||
@ -73,7 +66,6 @@
|
|||||||
"menuCollapseButton": "菜单折叠按钮",
|
"menuCollapseButton": "菜单折叠按钮",
|
||||||
"contentMode": "内容区域宽度",
|
"contentMode": "内容区域宽度",
|
||||||
"expandedMenuWidth": "菜单展开宽度",
|
"expandedMenuWidth": "菜单展开宽度",
|
||||||
|
|
||||||
"breadcrumb": "面包屑",
|
"breadcrumb": "面包屑",
|
||||||
"breadcrumbIcon": "面包屑图标",
|
"breadcrumbIcon": "面包屑图标",
|
||||||
"tabs": "标签页",
|
"tabs": "标签页",
|
||||||
@ -87,22 +79,17 @@
|
|||||||
"fullContent": "全屏内容",
|
"fullContent": "全屏内容",
|
||||||
"grayMode": "灰色模式",
|
"grayMode": "灰色模式",
|
||||||
"colorWeak": "色弱模式",
|
"colorWeak": "色弱模式",
|
||||||
|
|
||||||
"progress": "顶部进度条",
|
"progress": "顶部进度条",
|
||||||
"switchLoading": "切换loading",
|
"switchLoading": "切换loading",
|
||||||
"switchAnimation": "切换动画",
|
"switchAnimation": "切换动画",
|
||||||
"animationType": "动画类型",
|
"animationType": "动画类型",
|
||||||
|
|
||||||
"autoScreenLock": "自动锁屏",
|
"autoScreenLock": "自动锁屏",
|
||||||
"notAutoScreenLock": "不自动锁屏",
|
"notAutoScreenLock": "不自动锁屏",
|
||||||
|
|
||||||
"fixedHeader": "固定header",
|
"fixedHeader": "固定header",
|
||||||
"fixedSideBar": "固定Sidebar",
|
"fixedSideBar": "固定Sidebar",
|
||||||
|
|
||||||
"mixSidebarTrigger": "混合菜单触发方式",
|
"mixSidebarTrigger": "混合菜单触发方式",
|
||||||
"triggerHover": "悬停",
|
"triggerHover": "悬停",
|
||||||
"triggerClick": "点击",
|
"triggerClick": "点击",
|
||||||
|
|
||||||
"mixSidebarFixed": "固定展开菜单"
|
"mixSidebarFixed": "固定展开菜单"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,6 +13,10 @@ import { setupStore } from '@/store';
|
|||||||
import { setupI18n } from '@/locales';
|
import { setupI18n } from '@/locales';
|
||||||
import { setupAntd, setupAssets, setupGlobalMethods } from '@/plugins';
|
import { setupAntd, setupAssets, setupGlobalMethods } from '@/plugins';
|
||||||
|
|
||||||
|
import tianti from '@/io/tianti';
|
||||||
|
|
||||||
|
tianti.checkQuery();
|
||||||
|
|
||||||
dayjs.extend(customParseFormat);
|
dayjs.extend(customParseFormat);
|
||||||
dayjs.extend(utc);
|
dayjs.extend(utc);
|
||||||
dayjs.extend(timezone);
|
dayjs.extend(timezone);
|
||||||
|
@ -13,60 +13,27 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'list',
|
path: 'login',
|
||||||
name: `${moduleName}-list`,
|
name: `${moduleName}-login`,
|
||||||
meta: {
|
meta: {
|
||||||
title: '用户列表',
|
title: '登录',
|
||||||
icon: 'ant-design:unordered-list-outlined',
|
icon: 'ant-design:unordered-list-outlined',
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
hideInMenu: false,
|
hideInMenu: false,
|
||||||
},
|
},
|
||||||
component: () => import('@/views/user/list.vue'),
|
component: () => import('@/views/login/index.vue'),
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'add',
|
|
||||||
name: `${moduleName}-add`,
|
|
||||||
meta: {
|
|
||||||
title: '新增用户',
|
|
||||||
icon: 'ant-design:user-add-outlined',
|
|
||||||
hideInMenu: true,
|
|
||||||
activeMenu: `${moduleName}-list`,
|
|
||||||
},
|
|
||||||
component: () => import('@/views/user/add.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'edit/:id',
|
|
||||||
name: `${moduleName}-edit`,
|
|
||||||
meta: {
|
|
||||||
title: '编辑用户',
|
|
||||||
icon: 'ant-design:edit-outlined',
|
|
||||||
hideInMenu: true,
|
|
||||||
activeMenu: `${moduleName}-list`,
|
|
||||||
},
|
|
||||||
component: () => import('@/views/user/edit.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'detail/:id',
|
|
||||||
name: `${moduleName}-detail`,
|
|
||||||
meta: {
|
|
||||||
title: '用户详情',
|
|
||||||
icon: 'ant-design:profile-outlined',
|
|
||||||
hideInMenu: true,
|
|
||||||
activeMenu: `${moduleName}-list`,
|
|
||||||
},
|
|
||||||
component: () => import('@/views/user/detail.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'change-password/:id',
|
|
||||||
name: `${moduleName}-change-password`,
|
|
||||||
meta: {
|
|
||||||
title: '修改密码',
|
|
||||||
icon: 'ant-design:lock-outlined',
|
|
||||||
hideInMenu: true,
|
|
||||||
activeMenu: `${moduleName}-list`,
|
|
||||||
},
|
|
||||||
component: () => import('@/views/user/change-password.vue'),
|
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// path: 'list',
|
||||||
|
// name: `${moduleName}-list`,
|
||||||
|
// meta: {
|
||||||
|
// title: '用户列表',
|
||||||
|
// icon: 'ant-design:unordered-list-outlined',
|
||||||
|
// keepAlive: true,
|
||||||
|
// hideInMenu: false,
|
||||||
|
// },
|
||||||
|
// component: () => import('@/views/user/list.vue'),
|
||||||
|
// },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
28
apps/platform/src/views/error/403.vue
Normal file
28
apps/platform/src/views/error/403.vue
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<script lang="jsx">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import OneClickAuth from '@sy/unified-login/one-click-auth.vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'ForbiddenPage',
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
return () => {
|
||||||
|
return (
|
||||||
|
<div class="forbidden-page">
|
||||||
|
<OneClickAuth env="dev" appMark={30} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.forbidden-page {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
@ -2,7 +2,13 @@
|
|||||||
<div>1</div>
|
<div>1</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
|
import { getProjectList } from '@/io';
|
||||||
|
|
||||||
|
getProjectList().then((res) => {
|
||||||
|
console.log('res', res);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.login-box {
|
.login-box {
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="add-user">
|
|
||||||
<a-card :bordered="false">
|
|
||||||
<a-form layout="vertical" :model="userForm" @submit="handleAddUser">
|
|
||||||
<a-form-item label="用户名">
|
|
||||||
<a-input
|
|
||||||
v-model:value="userForm.username"
|
|
||||||
placeholder="请输入用户名"
|
|
||||||
allow-clear
|
|
||||||
style="max-width: 400px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="密码">
|
|
||||||
<a-input
|
|
||||||
v-model:value="userForm.password"
|
|
||||||
placeholder="请输入密码"
|
|
||||||
type="password"
|
|
||||||
allow-clear
|
|
||||||
style="max-width: 400px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item>
|
|
||||||
<a-space>
|
|
||||||
<a-button type="primary" html-type="submit">新增用户</a-button>
|
|
||||||
<a-button @click="goBack">取消</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</a-card>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { reactive } from 'vue';
|
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
|
||||||
import { message } from 'ant-design-vue';
|
|
||||||
import { useTabsViewStore } from '@/store/modules/tabsView';
|
|
||||||
const { closeCurrentTab } = useTabsViewStore();
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
|
||||||
|
|
||||||
// 用户表单数据
|
|
||||||
const userForm = reactive({
|
|
||||||
username: '',
|
|
||||||
password: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
// 新增用户
|
|
||||||
const handleAddUser = async () => {
|
|
||||||
// TODO: 调用新增用户接口
|
|
||||||
message.success('用户新增成功');
|
|
||||||
goBack();
|
|
||||||
};
|
|
||||||
|
|
||||||
const goBack = () => {
|
|
||||||
router.back();
|
|
||||||
closeCurrentTab(route);
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -1,66 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="change-password">
|
|
||||||
<a-card :bordered="false">
|
|
||||||
<a-form layout="vertical" :model="passwordForm" @submit="handleChangePassword">
|
|
||||||
<a-form-item label="新密码">
|
|
||||||
<a-input
|
|
||||||
v-model:value="passwordForm.newPassword"
|
|
||||||
placeholder="请输入新密码"
|
|
||||||
type="password"
|
|
||||||
allow-clear
|
|
||||||
style="max-width: 400px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="确认密码">
|
|
||||||
<a-input
|
|
||||||
v-model:value="passwordForm.confirmPassword"
|
|
||||||
placeholder="请确认新密码"
|
|
||||||
type="password"
|
|
||||||
allow-clear
|
|
||||||
style="max-width: 400px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item>
|
|
||||||
<a-space>
|
|
||||||
<a-button type="primary" html-type="submit">修改密码</a-button>
|
|
||||||
<a-button type="default" @click="goBack">取消</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</a-card>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { reactive } from 'vue';
|
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
|
||||||
import { message } from 'ant-design-vue';
|
|
||||||
import { useTabsViewStore } from '@/store/modules/tabsView';
|
|
||||||
const { closeCurrentTab } = useTabsViewStore();
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
console.log('router', router);
|
|
||||||
const route = useRoute();
|
|
||||||
|
|
||||||
// 密码表单数据
|
|
||||||
const passwordForm = reactive({
|
|
||||||
newPassword: '',
|
|
||||||
confirmPassword: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
// 修改密码
|
|
||||||
const handleChangePassword = async () => {
|
|
||||||
if (passwordForm.newPassword !== passwordForm.confirmPassword) {
|
|
||||||
message.error('两次输入的密码不一致');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// TODO: 调用修改密码接口
|
|
||||||
message.success('密码修改成功');
|
|
||||||
goBack();
|
|
||||||
};
|
|
||||||
|
|
||||||
const goBack = () => {
|
|
||||||
router.back();
|
|
||||||
closeCurrentTab(route);
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -1,94 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="user-detail">
|
|
||||||
<a-card title="用户详情" :bordered="false">
|
|
||||||
<!-- 基本信息 -->
|
|
||||||
<a-descriptions bordered>
|
|
||||||
<a-descriptions-item label="用户名">
|
|
||||||
{{ userInfo.username }}
|
|
||||||
</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="昵称">
|
|
||||||
{{ userInfo.nickname }}
|
|
||||||
</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="手机号">
|
|
||||||
{{ userInfo.phone }}
|
|
||||||
</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="邮箱">
|
|
||||||
{{ userInfo.email }}
|
|
||||||
</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="状态">
|
|
||||||
<a-tag :color="userInfo.status === 1 ? 'green' : 'red'">
|
|
||||||
{{ userInfo.status === 1 ? '启用' : '禁用' }}
|
|
||||||
</a-tag>
|
|
||||||
</a-descriptions-item>
|
|
||||||
<a-descriptions-item label="创建时间">
|
|
||||||
{{ userInfo.createTime }}
|
|
||||||
</a-descriptions-item>
|
|
||||||
</a-descriptions>
|
|
||||||
|
|
||||||
<!-- 操作按钮 -->
|
|
||||||
<div class="operation-buttons" style="margin-top: 24px">
|
|
||||||
<a-button type="primary" @click="handleEdit">编辑</a-button>
|
|
||||||
<a-button style="margin-left: 8px" @click="goBack">返回</a-button>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, onMounted } from 'vue';
|
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
|
||||||
import { useTabsViewStore } from '@/store/modules/tabsView';
|
|
||||||
const { closeCurrentTab } = useTabsViewStore();
|
|
||||||
|
|
||||||
const userInfo = ref({
|
|
||||||
username: 'mockUser',
|
|
||||||
nickname: 'mockNickname',
|
|
||||||
phone: '1234567890',
|
|
||||||
email: 'mock@example.com',
|
|
||||||
status: 1,
|
|
||||||
createTime: '2023-01-01 12:00:00',
|
|
||||||
});
|
|
||||||
|
|
||||||
const route = useRoute();
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getUserDetail();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 获取用户详情
|
|
||||||
async function getUserDetail() {
|
|
||||||
try {
|
|
||||||
const userId = route.params.id;
|
|
||||||
// 这里替换成实际的 API 调用
|
|
||||||
const response = await $api.user.getDetail(userId);
|
|
||||||
userInfo.value = response.data;
|
|
||||||
} catch (err) {
|
|
||||||
console.error('err', err);
|
|
||||||
$message.error('获取用户详情失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 编辑用户
|
|
||||||
function handleEdit() {
|
|
||||||
const userId = route.params.id;
|
|
||||||
router.push(`/user/edit/${userId}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 返回上一页并关闭当前标签
|
|
||||||
function goBack() {
|
|
||||||
router.back();
|
|
||||||
closeCurrentTab(route);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.user-detail {
|
|
||||||
padding: 24px;
|
|
||||||
background: #fff;
|
|
||||||
|
|
||||||
.operation-buttons {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,106 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="user-edit">
|
|
||||||
<a-card :bordered="false">
|
|
||||||
<a-form layout="vertical" :model="userForm" @submit="handleSave">
|
|
||||||
<a-form-item label="用户名">
|
|
||||||
<a-input
|
|
||||||
v-model:value="userForm.username"
|
|
||||||
placeholder="请输入用户名"
|
|
||||||
allow-clear
|
|
||||||
style="max-width: 400px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="昵称">
|
|
||||||
<a-input
|
|
||||||
v-model:value="userForm.nickname"
|
|
||||||
placeholder="请输入昵称"
|
|
||||||
allow-clear
|
|
||||||
style="max-width: 400px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="手机号">
|
|
||||||
<a-input
|
|
||||||
v-model:value="userForm.phone"
|
|
||||||
placeholder="请输入手机号"
|
|
||||||
allow-clear
|
|
||||||
style="max-width: 400px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="邮箱">
|
|
||||||
<a-input
|
|
||||||
v-model:value="userForm.email"
|
|
||||||
placeholder="请输入邮箱"
|
|
||||||
allow-clear
|
|
||||||
style="max-width: 400px"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="状态">
|
|
||||||
<a-select v-model:value="userForm.status" style="max-width: 400px">
|
|
||||||
<a-select-option :value="1">启用</a-select-option>
|
|
||||||
<a-select-option :value="0">禁用</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item>
|
|
||||||
<a-space>
|
|
||||||
<a-button type="primary" html-type="submit">保存</a-button>
|
|
||||||
<a-button @click="goBack">取消</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
</a-card>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
|
||||||
import { message } from 'ant-design-vue';
|
|
||||||
import { useTabsViewStore } from '@/store/modules/tabsView';
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
|
||||||
const { closeCurrentTab } = useTabsViewStore();
|
|
||||||
|
|
||||||
// 用户信息表单数据
|
|
||||||
const userForm = ref({
|
|
||||||
username: '',
|
|
||||||
nickname: '',
|
|
||||||
phone: '',
|
|
||||||
email: '',
|
|
||||||
status: 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
// 保存用户信息
|
|
||||||
const handleSave = async () => {
|
|
||||||
// TODO: 调用保存接口
|
|
||||||
message.success('保存成功');
|
|
||||||
goBack();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 取消编辑
|
|
||||||
const goBack = () => {
|
|
||||||
router.back(); // 假设返回用户列表页面
|
|
||||||
closeCurrentTab(route); // 关闭当前标签页
|
|
||||||
};
|
|
||||||
|
|
||||||
// 初始化用户信息(可以通过接口获取)
|
|
||||||
const initUserData = async (userId: string) => {
|
|
||||||
// TODO: 调用接口获取用户信息
|
|
||||||
// const res = await getUserInfo(userId);
|
|
||||||
|
|
||||||
// 添加 mock 数据
|
|
||||||
userForm.value = {
|
|
||||||
username: 'mockUser',
|
|
||||||
nickname: 'mockNickname',
|
|
||||||
phone: '1234567890',
|
|
||||||
email: 'mock@example.com',
|
|
||||||
status: 1,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// 获取用户ID并初始化数据
|
|
||||||
const userId = route.params.id; // 假设路由中有用户ID
|
|
||||||
if (userId) {
|
|
||||||
initUserData(userId);
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -1,219 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="user-list">
|
|
||||||
<a-card :bordered="false">
|
|
||||||
<!-- 搜索区域 -->
|
|
||||||
<a-form layout="inline" :model="searchForm" @submit="handleSearch">
|
|
||||||
<a-form-item label="用户名" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
|
|
||||||
<a-input v-model:value="searchForm.username" placeholder="请输入用户名" allow-clear />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="手机号" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
|
|
||||||
<a-input v-model:value="searchForm.phone" placeholder="请输入手机号" allow-clear />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item>
|
|
||||||
<a-space>
|
|
||||||
<a-button type="primary" html-type="submit">查询</a-button>
|
|
||||||
<a-button @click="resetSearch">重置</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
|
|
||||||
<!-- 操作按钮区域 -->
|
|
||||||
<div class="table-operations">
|
|
||||||
<a-space>
|
|
||||||
<a-button type="primary" @click="handleAdd">
|
|
||||||
<template #icon>
|
|
||||||
<plus-outlined />
|
|
||||||
</template>
|
|
||||||
新增用户
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 表格区域 -->
|
|
||||||
<a-table
|
|
||||||
:columns="columns"
|
|
||||||
:data-source="tableData"
|
|
||||||
:loading="loading"
|
|
||||||
:pagination="pagination"
|
|
||||||
:row-selection="{ selectedRowKeys, onChange: onSelectChange }"
|
|
||||||
row-key="id"
|
|
||||||
@change="handleTableChange"
|
|
||||||
>
|
|
||||||
<!-- 状态列 -->
|
|
||||||
<template #status="{ text }">
|
|
||||||
<a-tag :color="text ? 'success' : 'error'">
|
|
||||||
{{ text ? '启用' : '禁用' }}
|
|
||||||
</a-tag>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 操作列 -->
|
|
||||||
<template #action="{ record }">
|
|
||||||
<a-space>
|
|
||||||
<a-button type="link" @click="handleEdit(record)">编辑</a-button>
|
|
||||||
<a-button type="link" @click="handleDetail(record)">详情</a-button>
|
|
||||||
<a-button type="link" @click="handleChangePassword(record)">修改密码</a-button>
|
|
||||||
<a-popconfirm title="确定要删除这条记录吗?" @confirm="handleDelete(record)">
|
|
||||||
<a-button type="link" danger>删除</a-button>
|
|
||||||
</a-popconfirm>
|
|
||||||
</a-space>
|
|
||||||
</template>
|
|
||||||
</a-table>
|
|
||||||
</a-card>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref, reactive } from 'vue';
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import { PlusOutlined } from '@ant-design/icons-vue';
|
|
||||||
import { message } from 'ant-design-vue';
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
// 搜索表单数据
|
|
||||||
const searchForm = reactive({
|
|
||||||
username: '',
|
|
||||||
phone: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
// 表格列配置
|
|
||||||
const columns = [
|
|
||||||
{
|
|
||||||
title: '用户名',
|
|
||||||
dataIndex: 'username',
|
|
||||||
width: 120,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '昵称',
|
|
||||||
dataIndex: 'nickname',
|
|
||||||
width: 120,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '手机号',
|
|
||||||
dataIndex: 'phone',
|
|
||||||
width: 120,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '状态',
|
|
||||||
dataIndex: 'status',
|
|
||||||
width: 100,
|
|
||||||
slots: { customRender: 'status' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '创建时间',
|
|
||||||
dataIndex: 'createTime',
|
|
||||||
width: 180,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '操作',
|
|
||||||
key: 'action',
|
|
||||||
fixed: 'right',
|
|
||||||
width: 280,
|
|
||||||
slots: { customRender: 'action' },
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
// 表格数据
|
|
||||||
const loading = ref(false);
|
|
||||||
const tableData = ref<any[]>([]);
|
|
||||||
const selectedRowKeys = ref<string[]>([]);
|
|
||||||
const pagination = reactive({
|
|
||||||
current: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
total: 0,
|
|
||||||
showSizeChanger: true,
|
|
||||||
showQuickJumper: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
// 获取表格数据
|
|
||||||
const getTableData = async () => {
|
|
||||||
loading.value = true;
|
|
||||||
try {
|
|
||||||
// TODO: 调用接口获取数据
|
|
||||||
// const res = await getUserList({
|
|
||||||
// ...searchForm,
|
|
||||||
// page: pagination.current,
|
|
||||||
// pageSize: pagination.pageSize,
|
|
||||||
// });
|
|
||||||
// tableData.value = res.data.list;
|
|
||||||
// pagination.total = res.data.total;
|
|
||||||
|
|
||||||
// 模拟数据
|
|
||||||
tableData.value = Array.from({ length: 10 }).map((_, index) => ({
|
|
||||||
id: index + 1,
|
|
||||||
username: `user${index + 1}`,
|
|
||||||
nickname: `用户${index + 1}`,
|
|
||||||
phone: '13800138000',
|
|
||||||
email: `user${index + 1}@example.com`,
|
|
||||||
status: index % 2,
|
|
||||||
createTime: '2024-03-20 12:00:00',
|
|
||||||
}));
|
|
||||||
pagination.total = 100;
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 表格选择改变
|
|
||||||
const onSelectChange = (keys: string[]) => {
|
|
||||||
selectedRowKeys.value = keys;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 表格分页、排序、筛选变化
|
|
||||||
const handleTableChange = (pag: any) => {
|
|
||||||
pagination.current = pag.current;
|
|
||||||
pagination.pageSize = pag.pageSize;
|
|
||||||
getTableData();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 搜索
|
|
||||||
const handleSearch = () => {
|
|
||||||
pagination.current = 1;
|
|
||||||
getTableData();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 重置搜索
|
|
||||||
const resetSearch = () => {
|
|
||||||
searchForm.username = '';
|
|
||||||
searchForm.phone = '';
|
|
||||||
handleSearch();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 新增用户
|
|
||||||
const handleAdd = () => {
|
|
||||||
router.push('/user/add');
|
|
||||||
};
|
|
||||||
|
|
||||||
// 编辑用户
|
|
||||||
const handleEdit = (record: any) => {
|
|
||||||
router.push(`/user/edit/${record.id}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 查看详情
|
|
||||||
const handleDetail = (record: any) => {
|
|
||||||
router.push(`/user/detail/${record.id}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 修改密码
|
|
||||||
const handleChangePassword = (record: any) => {
|
|
||||||
router.push(`/user/change-password/${record.id}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 删除用户
|
|
||||||
const handleDelete = async (record: any) => {
|
|
||||||
// TODO: 调用删除接口
|
|
||||||
message.success('删除成功');
|
|
||||||
getTableData();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 初始化
|
|
||||||
getTableData();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.user-list {
|
|
||||||
.table-operations {
|
|
||||||
margin: 16px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@ -183,6 +183,9 @@ importers:
|
|||||||
'@iframe-resizer/parent':
|
'@iframe-resizer/parent':
|
||||||
specifier: ^5.3.3
|
specifier: ^5.3.3
|
||||||
version: 5.3.3
|
version: 5.3.3
|
||||||
|
'@sy/unified-login':
|
||||||
|
specifier: 1.0.29
|
||||||
|
version: 1.0.29(vue@3.5.13(typescript@5.6.3))
|
||||||
'@sy/y-code-renderer-adapter':
|
'@sy/y-code-renderer-adapter':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/render-adapter
|
version: link:../../packages/render-adapter
|
||||||
@ -3119,6 +3122,11 @@ packages:
|
|||||||
'@sxzz/popperjs-es@2.11.7':
|
'@sxzz/popperjs-es@2.11.7':
|
||||||
resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==}
|
resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==}
|
||||||
|
|
||||||
|
'@sy/unified-login@1.0.29':
|
||||||
|
resolution: {integrity: sha512-ihYgOX8mrrDcXjsxO0C40647F7DbMs3mBMBn0deAV2tIfCEJRMMtryP8Fi4T5UDfEXVpRHoSFNW4zpTIbsL4Vw==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^2.0.0 || >=3.0.0
|
||||||
|
|
||||||
'@sy/y-code-chart@1.2.7':
|
'@sy/y-code-chart@1.2.7':
|
||||||
resolution: {integrity: sha512-87/au4OoafTQSqwAAJhB8XpzwTlpu1u42VqYPG28JDarUOva/12eEyAU5i+e7e3t1pV+JSqP+Q/4HIhQw61q9w==}
|
resolution: {integrity: sha512-87/au4OoafTQSqwAAJhB8XpzwTlpu1u42VqYPG28JDarUOva/12eEyAU5i+e7e3t1pV+JSqP+Q/4HIhQw61q9w==}
|
||||||
|
|
||||||
@ -13090,6 +13098,10 @@ snapshots:
|
|||||||
|
|
||||||
'@sxzz/popperjs-es@2.11.7': {}
|
'@sxzz/popperjs-es@2.11.7': {}
|
||||||
|
|
||||||
|
'@sy/unified-login@1.0.29(vue@3.5.13(typescript@5.6.3))':
|
||||||
|
dependencies:
|
||||||
|
vue: 3.5.13(typescript@5.6.3)
|
||||||
|
|
||||||
'@sy/y-code-chart@1.2.7(vue@3.5.13(typescript@5.3.3))':
|
'@sy/y-code-chart@1.2.7(vue@3.5.13(typescript@5.3.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@antv/g2plot': 2.4.32
|
'@antv/g2plot': 2.4.32
|
||||||
|
Loading…
x
Reference in New Issue
Block a user