Merge branch 'develop' of github.com:Tencent/tdesign-vue-next-starter

This commit is contained in:
Uyarn 2023-05-18 17:58:42 +08:00
commit 9840fd4360
16 changed files with 85 additions and 60 deletions

6
.gitattributes vendored Normal file
View File

@ -0,0 +1,6 @@
*.ts text eol=lf
*.vue text eol=lf
*.tsx text eol=lf
*.jsx text eol=lf
*.html text eol=lf
*.json text eol=lf

View File

@ -1,15 +1,14 @@
# 文件名建议统一为 pull-request.yml # 文件名建议统一为 pull-request.yml
# 应用 test-build.yml 的 demo # 应用 test-build.yml 的 demo
name: MAIN_PULL_REQUEST name: MAIN_PULL_REQUEST
on: on:
pull_request: pull_request:
branches: [develop, main] branches: [develop, main, site]
types: [opened, synchronize, reopened] types: [opened, synchronize, reopened]
jobs: jobs:
call-test-build: call-test-build:
uses: Tencent/tdesign/.github/workflows/test-build.yml@main uses: Tencent/tdesign/.github/workflows/test-build.yml@main
# install lint
# install lint

View File

@ -1,4 +1,6 @@
{ {
"files.eol":"\n",
"editor.tabSize": 2,
"eslint.format.enable": true, "eslint.format.enable": true,
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "vue"], "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "vue"],
"[vue]": { "[vue]": {

View File

@ -1,6 +1,6 @@
{ {
"name": "tdesign-vue-next-starter", "name": "tdesign-vue-next-starter",
"version": "0.7.4", "version": "0.7.5",
"scripts": { "scripts": {
"dev:mock": "vite --open --mode mock", "dev:mock": "vite --open --mode mock",
"dev": "vite --open --mode development", "dev": "vite --open --mode development",

View File

@ -48,7 +48,7 @@
<template #icon> <template #icon>
<t-icon class="header-user-avatar" name="user-circle" /> <t-icon class="header-user-avatar" name="user-circle" />
</template> </template>
<div class="header-user-account">Tencent</div> <div class="header-user-account">{{ user.userInfo.name }}</div>
<template #suffix><t-icon name="chevron-down" /></template> <template #suffix><t-icon name="chevron-down" /></template>
</t-button> </t-button>
</t-dropdown> </t-dropdown>
@ -71,7 +71,7 @@ import { useRouter } from 'vue-router';
import LogoFull from '@/assets/assets-logo-full.svg?component'; import LogoFull from '@/assets/assets-logo-full.svg?component';
import { prefix } from '@/config/global'; import { prefix } from '@/config/global';
import { getActive } from '@/router'; import { getActive } from '@/router';
import { useSettingStore } from '@/store'; import { useSettingStore, useUserStore } from '@/store';
import type { MenuRoute } from '@/types/interface'; import type { MenuRoute } from '@/types/interface';
import MenuContent from './MenuContent.vue'; import MenuContent from './MenuContent.vue';
@ -111,6 +111,7 @@ const props = defineProps({
const router = useRouter(); const router = useRouter();
const settingStore = useSettingStore(); const settingStore = useSettingStore();
const user = useUserStore();
const toggleSettingPanel = () => { const toggleSettingPanel = () => {
settingStore.updateConfig({ settingStore.updateConfig({

View File

@ -1,7 +1,4 @@
import 'tdesign-vue-next/es/style/index.css'; /* eslint-disable simple-import-sort/imports */
import '@/style/index.less';
import './permission';
import TDesign from 'tdesign-vue-next'; import TDesign from 'tdesign-vue-next';
import { createApp } from 'vue'; import { createApp } from 'vue';
@ -9,6 +6,10 @@ import App from './App.vue';
import router from './router'; import router from './router';
import { store } from './store'; import { store } from './store';
import 'tdesign-vue-next/es/style/index.css';
import '@/style/index.less';
import './permission';
const app = createApp(App); const app = createApp(App);
app.use(TDesign); app.use(TDesign);

View File

@ -198,8 +198,8 @@ const onStokeDataChange = (checkedValues: string[]) => {
&__content { &__content {
&-title { &-title {
font: var(--td-font-headline-medium); font-size: var(--td-font-size-headline-medium);
font-weight: 400; line-height: var(--td-line-height-headline-medium);
} }
&-footer { &-footer {

View File

@ -191,8 +191,8 @@ watch(
> span { > span {
display: inline-block; display: inline-block;
color: var(--td-text-color-primary); color: var(--td-text-color-primary);
font: var(--td-font-headline-medium); font-size: var(--td-font-size-headline-medium);
font-weight: 400; line-height: var(--td-line-height-headline-medium);
} }
} }

View File

@ -29,7 +29,7 @@
@change="onMaterialChange" @change="onMaterialChange"
/> />
</template> </template>
<div id="lineContainer" style="width: 100%; height: 412px" /> <div id="lineContainer" style="width: 100%; height: 416px" />
</t-card> </t-card>
</t-col> </t-col>
<t-col :xs="12" :xl="3"> <t-col :xs="12" :xl="3">
@ -37,7 +37,7 @@
v-for="(item, index) in PRODUCT_LIST" v-for="(item, index) in PRODUCT_LIST"
:key="index" :key="index"
:product="item" :product="item"
:class="{ 'row-margin': index !== 0 }" :class="{ 'row-margin': index !== 0, 'product-card': true }"
/> />
</t-col> </t-col>
</t-row> </t-row>
@ -166,6 +166,23 @@ const onMaterialChange = (value: string[]) => {
margin-top: 16px; margin-top: 16px;
} }
.product-card {
padding: var(--td-comp-paddingTB-xl) var(--td-comp-paddingTB-xl);
:deep(.t-card__header) {
padding: 0;
}
:deep(.t-card__body) {
padding: 0;
margin-top: var(--td-comp-margin-xxl);
margin-bottom: var(--td-comp-margin-xxl);
}
:deep(.t-card__footer) {
padding: 0;
}
}
// 8px; // 8px;
.dashboard-detail-card { .dashboard-detail-card {
padding: var(--td-comp-paddingTB-xxl) var(--td-comp-paddingLR-xxl); padding: var(--td-comp-paddingTB-xxl) var(--td-comp-paddingLR-xxl);
@ -223,8 +240,8 @@ const onMaterialChange = (value: string[]) => {
} }
&__number { &__number {
font: var(--td-font-headline-large); font-size: var(--td-font-size-headline-medium);
font-weight: 400; line-height: var(--td-font-size-headline-medium);
color: var(--td-text-color-primary); color: var(--td-text-color-primary);
margin-bottom: var(--td-comp-margin-xxl); margin-bottom: var(--td-comp-margin-xxl);
} }

View File

@ -65,7 +65,7 @@ export default defineComponent({
height: 240px; height: 240px;
.operator-title-icon { .operator-title-icon {
background: var(--td-brand-color-focus); background: var(--td-brand-color-light);
color: var(--td-brand-color); color: var(--td-brand-color);
font-size: var(--td-comp-size-xxxl); font-size: var(--td-comp-size-xxxl);
padding: calc(var(--td-comp-size-xxxl) - var(--td-comp-size-xl)); padding: calc(var(--td-comp-size-xxxl) - var(--td-comp-size-xl));

View File

@ -56,7 +56,7 @@
border-radius: var(--td-radius-medium); border-radius: var(--td-radius-medium);
.product-sub-icon { .product-sub-icon {
background: var(--td-brand-color-focus); background: var(--td-brand-color-light);
color: var(--td-brand-color); color: var(--td-brand-color);
font-size: var(--td-comp-size-xxxl); font-size: var(--td-comp-size-xxxl);
padding: calc(var(--td-comp-size-xxxl) - var(--td-comp-size-xl)); padding: calc(var(--td-comp-size-xxxl) - var(--td-comp-size-xl));

View File

@ -104,7 +104,7 @@ const setReadStatus = (item: NotificationItem) => {
const changeMsg = msgData.value; const changeMsg = msgData.value;
changeMsg.forEach((e: NotificationItem) => { changeMsg.forEach((e: NotificationItem) => {
if (e.id === item.id) { if (e.id === item.id) {
if (e.status) e.status = false; e.status = !e.status;
} }
}); });
store.setMsgData(changeMsg); store.setMsgData(changeMsg);

View File

@ -4,6 +4,7 @@ import NProgress from 'nprogress'; // progress bar
import { MessagePlugin } from 'tdesign-vue-next'; import { MessagePlugin } from 'tdesign-vue-next';
import { RouteRecordRaw } from 'vue-router'; import { RouteRecordRaw } from 'vue-router';
import { TOKEN_NAME } from '@/config/global';
import router from '@/router'; import router from '@/router';
import { getPermissionStore, getUserStore } from '@/store'; import { getPermissionStore, getUserStore } from '@/store';
import { PAGE_NOT_FOUND_ROUTE } from '@/utils/route/constant'; import { PAGE_NOT_FOUND_ROUTE } from '@/utils/route/constant';
@ -17,41 +18,39 @@ router.beforeEach(async (to, from, next) => {
const { whiteListRouters } = permissionStore; const { whiteListRouters } = permissionStore;
const userStore = getUserStore(); const userStore = getUserStore();
const { token } = userStore;
if (token) { if (userStore[TOKEN_NAME]) {
if (to.path === '/login') { if (to.path === '/login') {
next(); next();
return; return;
} }
const { asyncRoutes } = permissionStore;
if (asyncRoutes && asyncRoutes.length === 0) {
const routeList = await permissionStore.buildAsyncRoutes();
routeList.forEach((item: RouteRecordRaw) => {
router.addRoute(item);
});
if (to.name === PAGE_NOT_FOUND_ROUTE.name) {
// 动态添加路由后此处应当重定向到fullPath否则会加载404页面内容
next({ path: to.fullPath, replace: true, query: to.query });
} else {
const redirect = decodeURIComponent((from.query.redirect || to.path) as string);
next(to.path === redirect ? { ...to, replace: true } : { path: redirect });
return;
}
}
try { try {
await userStore.getUserInfo(); await userStore.getUserInfo();
const { asyncRoutes } = permissionStore;
if (asyncRoutes && asyncRoutes.length === 0) {
const routeList = await permissionStore.buildAsyncRoutes();
routeList.forEach((item: RouteRecordRaw) => {
router.addRoute(item);
});
if (to.name === PAGE_NOT_FOUND_ROUTE.name) {
// 动态添加路由后此处应当重定向到fullPath否则会加载404页面内容
next({ path: to.fullPath, replace: true, query: to.query });
} else {
const redirect = decodeURIComponent((from.query.redirect || to.path) as string);
next(to.path === redirect ? { ...to, replace: true } : { path: redirect });
return;
}
}
if (router.hasRoute(to.name)) { if (router.hasRoute(to.name)) {
next(); next();
} else { } else {
next(`/`); next(`/`);
} }
} catch (error) { } catch (error) {
MessagePlugin.error(error); MessagePlugin.error(error.message);
next({ next({
path: '/login', path: '/login',
query: { redirect: encodeURIComponent(to.fullPath) }, query: { redirect: encodeURIComponent(to.fullPath) },

View File

@ -4,12 +4,13 @@ import { TOKEN_NAME } from '@/config/global';
import { store, usePermissionStore } from '@/store'; import { store, usePermissionStore } from '@/store';
const InitUserInfo = { const InitUserInfo = {
name: '', // 用户名,用于展示在页面右上角头像处
roles: [], // 前端权限模型使用 如果使用请配置modules/permission-fe.ts使用 roles: [], // 前端权限模型使用 如果使用请配置modules/permission-fe.ts使用
}; };
export const useUserStore = defineStore('user', { export const useUserStore = defineStore('user', {
state: () => ({ state: () => ({
token: localStorage.getItem(TOKEN_NAME) || 'main_token', // 默认token不走权限 [TOKEN_NAME]: 'main_token', // 默认token不走权限
userInfo: { ...InitUserInfo }, userInfo: { ...InitUserInfo },
}), }),
getters: { getters: {
@ -48,7 +49,7 @@ export const useUserStore = defineStore('user', {
const res = await mockLogin(userInfo); const res = await mockLogin(userInfo);
if (res.code === 200) { if (res.code === 200) {
this.token = res.data; this.setToken(res.data);
} else { } else {
throw res; throw res;
} }
@ -57,7 +58,7 @@ export const useUserStore = defineStore('user', {
const mockRemoteUserInfo = async (token: string) => { const mockRemoteUserInfo = async (token: string) => {
if (token === 'main_token') { if (token === 'main_token') {
return { return {
name: 'td_main', name: 'Tencent',
roles: ['all'], // 前端权限模型使用 如果使用请配置modules/permission-fe.ts使用 roles: ['all'], // 前端权限模型使用 如果使用请配置modules/permission-fe.ts使用
}; };
} }
@ -66,17 +67,19 @@ export const useUserStore = defineStore('user', {
roles: ['UserIndex', 'DashboardBase', 'login'], // 前端权限模型使用 如果使用请配置modules/permission-fe.ts使用 roles: ['UserIndex', 'DashboardBase', 'login'], // 前端权限模型使用 如果使用请配置modules/permission-fe.ts使用
}; };
}; };
const res = await mockRemoteUserInfo(this.token); const res = await mockRemoteUserInfo(this[TOKEN_NAME]);
this.userInfo = res; this.userInfo = res;
}, },
async logout() { async logout() {
localStorage.removeItem(TOKEN_NAME); this.removeToken();
this.token = '';
this.userInfo = { ...InitUserInfo }; this.userInfo = { ...InitUserInfo };
}, },
async removeToken() { async removeToken() {
this.token = ''; this.setToken('');
},
async setToken(token: string) {
this[TOKEN_NAME] = token;
}, },
}, },
persist: { persist: {
@ -84,6 +87,8 @@ export const useUserStore = defineStore('user', {
const permissionStore = usePermissionStore(); const permissionStore = usePermissionStore();
permissionStore.initRoutes(); permissionStore.initRoutes();
}, },
key: 'user',
paths: [TOKEN_NAME],
}, },
}); });

View File

@ -55,14 +55,6 @@
background: var(--td-gray-color-13); background: var(--td-gray-color-13);
} }
.t-default-menu:not(.t-menu--dark) .t-menu__item.t-is-active:not(.t-is-opened) {
background-color: var(--td-brand-color-1);
color: var(--td-brand-color);
.t-icon {
color: var(--td-brand-color);
}
}
.@{starter-prefix} { .@{starter-prefix} {
// 布局元素调整 // 布局元素调整
&-wrapper { &-wrapper {

View File

@ -5,6 +5,7 @@ import merge from 'lodash/merge';
import { TOKEN_NAME } from '@/config/global'; import { TOKEN_NAME } from '@/config/global';
import { ContentTypeEnum } from '@/constants'; import { ContentTypeEnum } from '@/constants';
import { getUserStore } from '@/store';
import { VAxios } from './Axios'; import { VAxios } from './Axios';
import type { AxiosTransform, CreateAxiosOptions } from './AxiosTransform'; import type { AxiosTransform, CreateAxiosOptions } from './AxiosTransform';
@ -113,7 +114,9 @@ const transform: AxiosTransform = {
// 请求拦截器处理 // 请求拦截器处理
requestInterceptors: (config, options) => { requestInterceptors: (config, options) => {
// 请求之前处理config // 请求之前处理config
const token = localStorage.getItem(TOKEN_NAME); const userStore = getUserStore();
const token = userStore[TOKEN_NAME];
if (token && (config as Recordable)?.requestOptions?.withToken !== false) { if (token && (config as Recordable)?.requestOptions?.withToken !== false) {
// jwt token // jwt token
(config as Recordable).headers.Authorization = options.authenticationScheme (config as Recordable).headers.Authorization = options.authenticationScheme