mirror of
https://github.com/Tencent/tdesign-vue-next-starter.git
synced 2024-12-23 05:56:36 +08:00
Merge pull request #708 from Tencent/develop
This commit is contained in:
commit
ce285fa443
|
@ -1,4 +1,4 @@
|
||||||
module.exports = {
|
export default {
|
||||||
// 一行最多 120 字符..
|
// 一行最多 120 字符..
|
||||||
printWidth: 120,
|
printWidth: 120,
|
||||||
// 使用 2 个空格缩进
|
// 使用 2 个空格缩进
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// commit-lint config
|
// commit-lint config
|
||||||
module.exports = {
|
export default {
|
||||||
extends: ['@commitlint/config-conventional'],
|
extends: ['@commitlint/config-conventional'],
|
||||||
rules: {
|
rules: {
|
||||||
'type-enum': [
|
'type-enum': [
|
||||||
|
|
70
package.json
70
package.json
|
@ -1,12 +1,14 @@
|
||||||
{
|
{
|
||||||
"name": "@tencent/tdesign-vue-next-starter",
|
"name": "@tencent/tdesign-vue-next-starter",
|
||||||
"version": "0.9.0",
|
"version": "0.10.0",
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev:mock": "vite --open --mode mock",
|
"dev:mock": "vite --open --mode mock",
|
||||||
"dev": "vite --open --mode development",
|
"dev": "vite --open --mode development",
|
||||||
"dev:linux": "vite --mode development",
|
"dev:linux": "vite --mode development",
|
||||||
"build:test": "vite build --mode test",
|
"build:test": "vite build --mode test",
|
||||||
"build": "vue-tsc --noEmit && vite build --mode release",
|
"build": "vue-tsc --noEmit && vite build --mode release",
|
||||||
|
"build:type": "vue-tsc --noEmit",
|
||||||
"build:site": "vue-tsc --noEmit && vite build --mode site",
|
"build:site": "vue-tsc --noEmit && vite build --mode site",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"lint": "eslint --ext .vue,.js,.jsx,.ts,.tsx ./ --max-warnings 0",
|
"lint": "eslint --ext .vue,.js,.jsx,.ts,.tsx ./ --max-warnings 0",
|
||||||
|
@ -19,10 +21,10 @@
|
||||||
"test:coverage": "echo \"no test:coverage specified,work in process\""
|
"test:coverage": "echo \"no test:coverage specified,work in process\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vueuse/core": "^10.6.1",
|
"@vueuse/core": "^10.7.2",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.7",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"echarts": "5.1.2",
|
"echarts": "5.4.3",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
|
@ -30,50 +32,50 @@
|
||||||
"qrcode.vue": "^3.4.1",
|
"qrcode.vue": "^3.4.1",
|
||||||
"qs": "^6.11.2",
|
"qs": "^6.11.2",
|
||||||
"tdesign-icons-vue-next": "^0.2.2",
|
"tdesign-icons-vue-next": "^0.2.2",
|
||||||
"tdesign-vue-next": "^1.6.8",
|
"tdesign-vue-next": "^1.9.3",
|
||||||
"tvision-color": "^1.6.0",
|
"tvision-color": "^1.6.0",
|
||||||
"vue": "~3.3.8",
|
"vue": "~3.4.21",
|
||||||
"vue-i18n": "^9.6.5",
|
"vue-i18n": "^9.9.1",
|
||||||
"vue-router": "~4.2.4"
|
"vue-router": "~4.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^18.4.1",
|
"@commitlint/cli": "^18.6.0",
|
||||||
"@commitlint/config-conventional": "^18.4.0",
|
"@commitlint/config-conventional": "^18.6.0",
|
||||||
"@types/echarts": "^4.9.21",
|
"@types/echarts": "^4.9.21",
|
||||||
"@types/lodash": "^4.14.201",
|
"@types/lodash": "^4.14.201",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@types/qs": "^6.9.10",
|
"@types/qs": "^6.9.11",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||||
"@typescript-eslint/parser": "^6.11.0",
|
"@typescript-eslint/parser": "^6.21.0",
|
||||||
"@vitejs/plugin-vue": "^4.4.1",
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
"@vitejs/plugin-vue-jsx": "^3.0.2",
|
"@vitejs/plugin-vue-jsx": "^3.0.2",
|
||||||
"@vue/compiler-sfc": "^3.3.8",
|
"@vue/compiler-sfc": "~3.3.8",
|
||||||
"@vue/eslint-config-typescript": "^12.0.0",
|
"@vue/eslint-config-typescript": "^12.0.0",
|
||||||
"commitizen": "^4.3.0",
|
"commitizen": "^4.3.0",
|
||||||
"cz-conventional-changelog": "^3.3.0",
|
"cz-conventional-changelog": "^3.3.0",
|
||||||
"eslint": "^8.53.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^9.0.0",
|
||||||
"eslint-plugin-import": "^2.29.0",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"eslint-plugin-prettier": "^5.0.1",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
"eslint-plugin-simple-import-sort": "^12.0.0",
|
||||||
"eslint-plugin-vue": "^9.18.1",
|
"eslint-plugin-vue": "^9.21.1",
|
||||||
"eslint-plugin-vue-scoped-css": "^2.5.1",
|
"eslint-plugin-vue-scoped-css": "^2.7.2",
|
||||||
"husky": "^8.0.3",
|
"husky": "^9.0.10",
|
||||||
"less": "^4.2.0",
|
"less": "^4.2.0",
|
||||||
"lint-staged": "^15.1.0",
|
"lint-staged": "^15.2.2",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"postcss-html": "^1.5.0",
|
"postcss-html": "^1.6.0",
|
||||||
"postcss-less": "^6.0.0",
|
"postcss-less": "^6.0.0",
|
||||||
"prettier": "^3.1.0",
|
"prettier": "^3.2.5",
|
||||||
"stylelint": "~15.11.0",
|
"stylelint": "~16.2.1",
|
||||||
"stylelint-config-standard": "^34.0.0",
|
"stylelint-config-standard": "^36.0.0",
|
||||||
"stylelint-order": "~6.0.3",
|
"stylelint-order": "~6.0.4",
|
||||||
"typescript": "~5.3.2",
|
"typescript": "~5.4.3",
|
||||||
"vite": "^4.5.0",
|
"vite": "^5.1.0",
|
||||||
"vite-plugin-mock": "^3.0.0",
|
"vite-plugin-mock": "^3.0.1",
|
||||||
"vite-svg-loader": "^4.0.0",
|
"vite-svg-loader": "^5.1.0",
|
||||||
"vue-tsc": "^1.8.22"
|
"vue-tsc": "^1.8.27"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"commitizen": {
|
"commitizen": {
|
||||||
|
@ -90,6 +92,6 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.0.0"
|
"node": ">=18.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<t-config-provider :global-config="getComponentsLocale">
|
<t-config-provider :global-config="getComponentsLocale">
|
||||||
<router-view :key="locale" :class="[mode]"
|
<router-view :key="locale" :class="[mode]" />
|
||||||
/></t-config-provider>
|
</t-config-provider>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
|
@ -5,6 +5,7 @@ export default {
|
||||||
mode: 'light',
|
mode: 'light',
|
||||||
layout: 'side',
|
layout: 'side',
|
||||||
splitMenu: false,
|
splitMenu: false,
|
||||||
|
sideMode: 'light',
|
||||||
isFooterAside: false,
|
isFooterAside: false,
|
||||||
isSidebarFixed: true,
|
isSidebarFixed: true,
|
||||||
isHeaderFixed: true,
|
isHeaderFixed: true,
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
import debounce from 'lodash/debounce';
|
|
||||||
import { onMounted, onUnmounted } from 'vue';
|
|
||||||
|
|
||||||
interface WindowSizeOptions {
|
|
||||||
immediate?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Fn<T = any, R = T> {
|
|
||||||
(...arg: T[]): R;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useWindowSizeFn<T>(fn: Fn<T>, options?: WindowSizeOptions, wait = 150) {
|
|
||||||
const handleSize: () => void = debounce(fn, wait);
|
|
||||||
|
|
||||||
const start = () => {
|
|
||||||
if (options && options.immediate) {
|
|
||||||
fn();
|
|
||||||
}
|
|
||||||
window.addEventListener('resize', handleSize);
|
|
||||||
};
|
|
||||||
|
|
||||||
const stop = () => {
|
|
||||||
window.removeEventListener('resize', handleSize);
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
start();
|
|
||||||
});
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
stop();
|
|
||||||
});
|
|
||||||
return [start, stop];
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<router-view v-if="!isRefreshing" v-slot="{ Component }">
|
<router-view v-if="!isRefreshing" v-slot="{ Component }">
|
||||||
<transition name="fade">
|
<transition name="fade" mode="out-in">
|
||||||
<keep-alive :include="aliveViews">
|
<keep-alive :include="aliveViews">
|
||||||
<component :is="Component" />
|
<component :is="Component" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
|
@ -54,7 +54,7 @@ const isRefreshing = computed(() => {
|
||||||
transition: opacity @anim-duration-slow @anim-time-fn-easing;
|
transition: opacity @anim-duration-slow @anim-time-fn-easing;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-enter,
|
.fade-enter-from,
|
||||||
.fade-leave-to {
|
.fade-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,17 +6,19 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { useWindowSize } from '@vueuse/core';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import { computed, CSSProperties, ref, unref, watch } from 'vue';
|
import { computed, CSSProperties, ref, unref, watch } from 'vue';
|
||||||
|
|
||||||
import { prefix } from '@/config/global';
|
import { prefix } from '@/config/global';
|
||||||
import { useWindowSizeFn } from '@/hooks/event/useWindowSizeFn';
|
|
||||||
import { useSettingStore } from '@/store';
|
import { useSettingStore } from '@/store';
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
frameSrc: String,
|
frameSrc: String,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { width, height } = useWindowSize();
|
||||||
|
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const heightRef = ref(window.innerHeight);
|
const heightRef = ref(window.innerHeight);
|
||||||
const frameRef = ref<HTMLFrameElement>();
|
const frameRef = ref<HTMLFrameElement>();
|
||||||
|
@ -69,8 +71,8 @@ function hideLoading() {
|
||||||
calcHeight();
|
calcHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
useWindowSizeFn(calcHeight, { immediate: true });
|
// 如果窗口大小发生变化
|
||||||
|
watch([width, height], debounce(calcHeight, 250));
|
||||||
watch(
|
watch(
|
||||||
[() => settingStore.showFooter, () => settingStore.isUseTabsRouter, () => settingStore.showBreadcrumb],
|
[() => settingStore.showFooter, () => settingStore.isUseTabsRouter, () => settingStore.showBreadcrumb],
|
||||||
debounce(calcHeight, 250),
|
debounce(calcHeight, 250),
|
||||||
|
|
|
@ -38,9 +38,13 @@
|
||||||
<translate-icon />
|
<translate-icon />
|
||||||
</t-button>
|
</t-button>
|
||||||
<t-dropdown-menu>
|
<t-dropdown-menu>
|
||||||
<t-dropdown-item v-for="(lang, index) in langList" :key="index" :value="lang.value" @click="changeLang">{{
|
<t-dropdown-item
|
||||||
lang.content
|
v-for="(lang, index) in langList"
|
||||||
}}</t-dropdown-item></t-dropdown-menu
|
:key="index"
|
||||||
|
:value="lang.value"
|
||||||
|
@click="(options) => changeLang(options.value as string)"
|
||||||
|
>{{ lang.content }}</t-dropdown-item
|
||||||
|
></t-dropdown-menu
|
||||||
>
|
>
|
||||||
</t-dropdown>
|
</t-dropdown>
|
||||||
<t-dropdown :min-column-width="120" trigger="click">
|
<t-dropdown :min-column-width="120" trigger="click">
|
||||||
|
@ -85,7 +89,7 @@ import { langList } from '@/locales/index';
|
||||||
import { useLocale } from '@/locales/useLocale';
|
import { useLocale } from '@/locales/useLocale';
|
||||||
import { getActive } from '@/router';
|
import { getActive } from '@/router';
|
||||||
import { useSettingStore, useUserStore } from '@/store';
|
import { useSettingStore, useUserStore } from '@/store';
|
||||||
import type { MenuRoute } from '@/types/interface';
|
import type { MenuRoute, ModeType } from '@/types/interface';
|
||||||
|
|
||||||
import MenuContent from './MenuContent.vue';
|
import MenuContent from './MenuContent.vue';
|
||||||
import Notice from './Notice.vue';
|
import Notice from './Notice.vue';
|
||||||
|
@ -147,11 +151,11 @@ const menuCls = computed(() => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
const menuTheme = computed(() => props.theme as 'light' | 'dark');
|
const menuTheme = computed(() => props.theme as ModeType);
|
||||||
|
|
||||||
// 切换语言
|
// 切换语言
|
||||||
const { changeLocale } = useLocale();
|
const { changeLocale } = useLocale();
|
||||||
const changeLang = ({ value: lang }: { value: string }) => {
|
const changeLang = (lang: string) => {
|
||||||
changeLocale(lang);
|
changeLocale(lang);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -238,7 +242,6 @@ const navToHelper = () => {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: normal;
|
align-items: normal;
|
||||||
line-height: 0;
|
line-height: 0;
|
||||||
padding-left: var(--td-comp-margin-xl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-logo-container {
|
.header-logo-container {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
:class="`${prefix}-layout-tabs-nav`"
|
:class="`${prefix}-layout-tabs-nav`"
|
||||||
:value="$route.path"
|
:value="$route.path"
|
||||||
:style="{ position: 'sticky', top: 0, width: '100%' }"
|
:style="{ position: 'sticky', top: 0, width: '100%' }"
|
||||||
@change="handleChangeCurrentTab"
|
@change="(value) => handleChangeCurrentTab(value as string)"
|
||||||
@remove="handleRemove"
|
@remove="handleRemove"
|
||||||
@drag-sort="handleDragend"
|
@drag-sort="handleDragend"
|
||||||
>
|
>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
:layout="settingStore.layout"
|
:layout="settingStore.layout"
|
||||||
:is-fixed="settingStore.isSidebarFixed"
|
:is-fixed="settingStore.isSidebarFixed"
|
||||||
:menu="sideMenu"
|
:menu="sideMenu"
|
||||||
:theme="settingStore.displayMode"
|
:theme="settingStore.displaySideMode"
|
||||||
:is-compact="settingStore.isSidebarCompact"
|
:is-compact="settingStore.isSidebarCompact"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -3,12 +3,12 @@
|
||||||
<t-menu :class="menuCls" :theme="theme" :value="active" :collapsed="collapsed" :default-expanded="defaultExpanded">
|
<t-menu :class="menuCls" :theme="theme" :value="active" :collapsed="collapsed" :default-expanded="defaultExpanded">
|
||||||
<template #logo>
|
<template #logo>
|
||||||
<span v-if="showLogo" :class="`${prefix}-side-nav-logo-wrapper`" @click="goHome">
|
<span v-if="showLogo" :class="`${prefix}-side-nav-logo-wrapper`" @click="goHome">
|
||||||
<component :is="getLogo()" :class="`${prefix}-side-nav-logo-${collapsed ? 't' : 'tdesign'}-logo`" />
|
<component :is="getLogo()" :class="logoCls" />
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<menu-content :nav-data="menu" />
|
<menu-content :nav-data="menu" />
|
||||||
<template #operations>
|
<template #operations>
|
||||||
<span class="version-container"> {{ !collapsed ? 'TDesign Starter' : '' }} {{ pgk.version }} </span>
|
<span :class="versionCls"> {{ !collapsed ? 'TDesign Starter' : '' }} {{ pgk.version }} </span>
|
||||||
</template>
|
</template>
|
||||||
</t-menu>
|
</t-menu>
|
||||||
<div :class="`${prefix}-side-nav-placeholder${collapsed ? '-hidden' : ''}`"></div>
|
<div :class="`${prefix}-side-nav-placeholder${collapsed ? '-hidden' : ''}`"></div>
|
||||||
|
@ -26,7 +26,7 @@ import AssetLogo from '@/assets/assets-t-logo.svg?component';
|
||||||
import { prefix } from '@/config/global';
|
import { prefix } from '@/config/global';
|
||||||
import { getActive, getRoutesExpanded } from '@/router';
|
import { getActive, getRoutesExpanded } from '@/router';
|
||||||
import { useSettingStore } from '@/store';
|
import { useSettingStore } from '@/store';
|
||||||
import type { MenuRoute } from '@/types/interface';
|
import type { MenuRoute, ModeType } from '@/types/interface';
|
||||||
|
|
||||||
import pgk from '../../../package.json';
|
import pgk from '../../../package.json';
|
||||||
import MenuContent from './MenuContent.vue';
|
import MenuContent from './MenuContent.vue';
|
||||||
|
@ -55,7 +55,7 @@ const props = defineProps({
|
||||||
default: '64px',
|
default: '64px',
|
||||||
},
|
},
|
||||||
theme: {
|
theme: {
|
||||||
type: String as PropType<'light' | 'dark'>,
|
type: String as PropType<ModeType>,
|
||||||
default: 'light',
|
default: 'light',
|
||||||
},
|
},
|
||||||
isCompact: {
|
isCompact: {
|
||||||
|
@ -75,6 +75,10 @@ const defaultExpanded = computed(() => {
|
||||||
return union(expanded, parentPath === '' ? [] : [parentPath]);
|
return union(expanded, parentPath === '' ? [] : [parentPath]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const sideMode = computed(() => {
|
||||||
|
const { theme } = props;
|
||||||
|
return theme === 'dark';
|
||||||
|
});
|
||||||
const sideNavCls = computed(() => {
|
const sideNavCls = computed(() => {
|
||||||
const { isCompact } = props;
|
const { isCompact } = props;
|
||||||
return [
|
return [
|
||||||
|
@ -84,7 +88,22 @@ const sideNavCls = computed(() => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
const logoCls = computed(() => {
|
||||||
|
return [
|
||||||
|
`${prefix}-side-nav-logo-${collapsed.value ? 't' : 'tdesign'}-logo`,
|
||||||
|
{
|
||||||
|
[`${prefix}-side-nav-dark`]: sideMode.value,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
const versionCls = computed(() => {
|
||||||
|
return [
|
||||||
|
`version-container`,
|
||||||
|
{
|
||||||
|
[`${prefix}-side-nav-dark`]: sideMode.value,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
const menuCls = computed(() => {
|
const menuCls = computed(() => {
|
||||||
const { showLogo, isFixed, layout } = props;
|
const { showLogo, isFixed, layout } = props;
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -52,7 +52,6 @@
|
||||||
</t-popup>
|
</t-popup>
|
||||||
</div>
|
</div>
|
||||||
</t-radio-group>
|
</t-radio-group>
|
||||||
|
|
||||||
<div class="setting-group-title">{{ $t('layout.setting.navigationLayout') }}</div>
|
<div class="setting-group-title">{{ $t('layout.setting.navigationLayout') }}</div>
|
||||||
<t-radio-group v-model="formData.layout">
|
<t-radio-group v-model="formData.layout">
|
||||||
<div v-for="(item, index) in LAYOUT_OPTION" :key="index" class="setting-layout-drawer">
|
<div v-for="(item, index) in LAYOUT_OPTION" :key="index" class="setting-layout-drawer">
|
||||||
|
@ -62,15 +61,24 @@
|
||||||
</div>
|
</div>
|
||||||
</t-radio-group>
|
</t-radio-group>
|
||||||
|
|
||||||
<t-form-item v-show="formData.layout === 'mix'" label="分割菜单(混合模式下有效)" name="splitMenu">
|
<t-form-item v-show="formData.layout === 'mix'" :label="$t('layout.setting.splitMenu')" name="splitMenu">
|
||||||
<t-switch v-model="formData.splitMenu" />
|
<t-switch v-model="formData.splitMenu" />
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
|
<t-form-item
|
||||||
<t-form-item v-show="formData.layout === 'mix'" label="固定 Sidebar" name="isSidebarFixed">
|
v-show="formData.layout === 'mix'"
|
||||||
|
:label="$t('layout.setting.fixedSidebar')"
|
||||||
|
name="isSidebarFixed"
|
||||||
|
>
|
||||||
<t-switch v-model="formData.isSidebarFixed" />
|
<t-switch v-model="formData.isSidebarFixed" />
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
|
|
||||||
<div class="setting-group-title">{{ $t('layout.setting.element.title') }}</div>
|
<div class="setting-group-title">{{ $t('layout.setting.element.title') }}</div>
|
||||||
|
<t-form-item :label="$t('layout.setting.sideMode')" name="sideMode">
|
||||||
|
<t-radio-group v-model="formData.sideMode" class="side-mode-radio">
|
||||||
|
<t-radio-button key="light" value="light" :label="$t('layout.setting.theme.options.light')" />
|
||||||
|
<t-radio-button key="dark" value="dark" :label="$t('layout.setting.theme.options.dark')" />
|
||||||
|
</t-radio-group>
|
||||||
|
</t-form-item>
|
||||||
<t-form-item
|
<t-form-item
|
||||||
v-show="formData.layout === 'side'"
|
v-show="formData.layout === 'side'"
|
||||||
:label="$t('layout.setting.element.showHeader')"
|
:label="$t('layout.setting.element.showHeader')"
|
||||||
|
@ -295,6 +303,10 @@ watchEffect(() => {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
&.side-mode-radio {
|
||||||
|
justify-content: end;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.t-radio-group.t-size-m .t-radio-button {
|
.t-radio-group.t-size-m .t-radio-button {
|
||||||
|
|
|
@ -33,6 +33,7 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
navigationLayout: 'Navigation Layout',
|
navigationLayout: 'Navigation Layout',
|
||||||
|
sideMode: 'Side Menu Mode',
|
||||||
splitMenu: 'Split Menu(Only Mix mode)',
|
splitMenu: 'Split Menu(Only Mix mode)',
|
||||||
fixedSidebar: 'Fixed Sidebar',
|
fixedSidebar: 'Fixed Sidebar',
|
||||||
element: {
|
element: {
|
||||||
|
|
|
@ -33,6 +33,7 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
navigationLayout: '导航布局',
|
navigationLayout: '导航布局',
|
||||||
|
sideMode: '侧边栏模式',
|
||||||
splitMenu: '分割菜单(混合模式下有效)',
|
splitMenu: '分割菜单(混合模式下有效)',
|
||||||
fixedSidebar: '固定侧边栏',
|
fixedSidebar: '固定侧边栏',
|
||||||
element: {
|
element: {
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
theme="primary"
|
theme="primary"
|
||||||
mode="date"
|
mode="date"
|
||||||
:default-value="LAST_7_DAYS"
|
:default-value="LAST_7_DAYS"
|
||||||
@change="onCurrencyChange"
|
@change="(value) => onCurrencyChange(value as string[])"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -97,6 +97,25 @@ const renderCountChart = () => {
|
||||||
}
|
}
|
||||||
countChart = echarts.init(countContainer);
|
countChart = echarts.init(countContainer);
|
||||||
countChart.setOption(getPieChartDataSet(chartColors.value));
|
countChart.setOption(getPieChartDataSet(chartColors.value));
|
||||||
|
|
||||||
|
// 取消之前高亮的图形
|
||||||
|
countChart.dispatchAction({
|
||||||
|
type: 'downplay',
|
||||||
|
seriesIndex: 0,
|
||||||
|
dataIndex: -1,
|
||||||
|
});
|
||||||
|
// 高亮当前图形
|
||||||
|
countChart.dispatchAction({
|
||||||
|
type: 'highlight',
|
||||||
|
seriesIndex: 0,
|
||||||
|
dataIndex: 1,
|
||||||
|
});
|
||||||
|
// 显示 tooltip
|
||||||
|
countChart.dispatchAction({
|
||||||
|
type: 'showTip',
|
||||||
|
seriesIndex: 0,
|
||||||
|
dataIndex: 1,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderCharts = () => {
|
const renderCharts = () => {
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
theme="primary"
|
theme="primary"
|
||||||
mode="date"
|
mode="date"
|
||||||
:default-value="LAST_7_DAYS"
|
:default-value="LAST_7_DAYS"
|
||||||
@change="onStokeDataChange"
|
@change="(value) => onStokeDataChange(value as string[])"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<div id="stokeContainer" style="width: 100%; height: 351px" class="dashboard-chart-container"></div>
|
<div id="stokeContainer" style="width: 100%; height: 351px" class="dashboard-chart-container"></div>
|
||||||
|
|
|
@ -367,8 +367,7 @@ export function getPieChartDataSet({
|
||||||
emphasis: {
|
emphasis: {
|
||||||
scale: true,
|
scale: true,
|
||||||
label: {
|
label: {
|
||||||
show: true,
|
show: false,
|
||||||
formatter: ['{value|{d}%}', '{name|{b}渠道占比}'].join('\n'),
|
|
||||||
rich: {
|
rich: {
|
||||||
value: {
|
value: {
|
||||||
color: textColor,
|
color: textColor,
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
theme="primary"
|
theme="primary"
|
||||||
mode="date"
|
mode="date"
|
||||||
style="width: 248px"
|
style="width: 248px"
|
||||||
@change="onMaterialChange"
|
@change="(value) => onMaterialChange(value as string[])"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<div id="lineContainer" style="width: 100%; height: 416px" />
|
<div id="lineContainer" style="width: 100%; height: 416px" />
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="detail-advanced">
|
<div class="detail-advanced">
|
||||||
<t-card :title="$t('pages.detailCard.baseInfo.title')" :bordered="false">
|
<t-card :bordered="false">
|
||||||
<div class="info-block">
|
<t-descriptions :title="$t('pages.detailCard.baseInfo.title')">
|
||||||
<div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item">
|
<t-descriptions-item v-for="(item, index) in BASE_INFO_DATA" :key="index" :label="item.name">
|
||||||
<h1>{{ item.name }}</h1>
|
|
||||||
<span
|
<span
|
||||||
:class="{
|
:class="{
|
||||||
['inProgress']: item.type && item.type.value === 'inProgress',
|
['inProgress']: item.type && item.type.value === 'inProgress',
|
||||||
|
@ -13,8 +12,8 @@
|
||||||
<i v-if="item.type && item.type.key === 'contractStatus'" />
|
<i v-if="item.type && item.type.key === 'contractStatus'" />
|
||||||
{{ item.value }}
|
{{ item.value }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</t-descriptions-item>
|
||||||
</div>
|
</t-descriptions>
|
||||||
</t-card>
|
</t-card>
|
||||||
|
|
||||||
<!-- 发票进度 -->
|
<!-- 发票进度 -->
|
||||||
|
@ -113,18 +112,19 @@
|
||||||
<t-dialog v-model:visible="visible" :header="$t('pages.detailCard.baseInfo.title')" @confirm="onConfirm">
|
<t-dialog v-model:visible="visible" :header="$t('pages.detailCard.baseInfo.title')" @confirm="onConfirm">
|
||||||
<template #body>
|
<template #body>
|
||||||
<div class="dialog-info-block">
|
<div class="dialog-info-block">
|
||||||
<div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item">
|
<t-descriptions :column="1">
|
||||||
<h1>{{ item.name }}</h1>
|
<t-descriptions-item v-for="(item, index) in BASE_INFO_DATA" :key="index" :label="item.name">
|
||||||
<span
|
<span
|
||||||
:class="{
|
:class="{
|
||||||
['inProgress']: item.type && item.type.value === 'inProgress',
|
['inProgress']: item.type && item.type.value === 'inProgress',
|
||||||
['pdf']: item.type && item.type.value === 'pdf',
|
['pdf']: item.type && item.type.value === 'pdf',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<i v-if="item.type && item.type.key === 'contractStatus'" />
|
<i v-if="item.type && item.type.key === 'contractStatus'" />
|
||||||
{{ item.value }}
|
{{ item.value }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</t-descriptions-item>
|
||||||
|
</t-descriptions>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</t-dialog>
|
</t-dialog>
|
||||||
|
|
|
@ -1,112 +1,28 @@
|
||||||
.detail-base {
|
.t-descriptions {
|
||||||
:deep(.t-card) {
|
|
||||||
padding: var(--td-comp-paddingTB-xxl) var(--td-comp-paddingLR-xxl);
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.t-card__header) {
|
|
||||||
padding: 0;
|
|
||||||
margin-bottom: var(--td-comp-margin-m);
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.t-card__body) {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.t-card__title) {
|
|
||||||
font: var(--td-font-title-large);
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-info-steps {
|
|
||||||
padding-top: var(--td-comp-margin-xl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-block {
|
|
||||||
column-count: 2;
|
|
||||||
|
|
||||||
.info-item {
|
|
||||||
padding-top: var(--td-comp-margin-xxl);
|
|
||||||
display: flex;
|
|
||||||
color: var(--td-text-color-primary);
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
width: 160px;
|
|
||||||
font: var(--td-font-body-medium);
|
|
||||||
color: var(--td-text-color-secondary);
|
|
||||||
font-weight: normal;
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
@media (max-width: @screen-sm-max) {
|
|
||||||
width: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: @screen-md-min) and (max-width: @screen-md-max) {
|
|
||||||
width: 120px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
span {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
margin-left: var(--td-comp-margin-xxl);
|
margin-left: var(--td-comp-margin-xxl);
|
||||||
}
|
}
|
||||||
|
|
||||||
i {
|
i {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
border-radius: var(--td-radius-circle);
|
border-radius: var(--td-radius-circle);
|
||||||
background: var(--td-success-color);
|
background: var(--td-success-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.inProgress {
|
.inProgress {
|
||||||
color: var(--td-success-color);
|
color: var(--td-success-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pdf {
|
.pdf {
|
||||||
color: var(--td-brand-color);
|
color: var(--td-brand-color);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-info-block {
|
|
||||||
.info-item {
|
|
||||||
padding: 12px 0;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
width: 84px;
|
|
||||||
font-family: var(--td-font-family);
|
|
||||||
font-size: 14px;
|
|
||||||
color: var(--td-text-color-secondary);
|
|
||||||
text-align: left;
|
|
||||||
line-height: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
margin-left: var(--td-comp-margin-xxl);
|
|
||||||
}
|
|
||||||
|
|
||||||
i {
|
|
||||||
display: inline-block;
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
border-radius: var(--td-radius-circle);
|
|
||||||
background: var(--td-success-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.green {
|
|
||||||
color: var(--td-success-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.blue {
|
|
||||||
color: var(--td-brand-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="detail-base">
|
<div class="detail-base">
|
||||||
<t-card :title="$t('pages.detailBase.baseInfo.title')" :bordered="false">
|
<t-card :bordered="false">
|
||||||
<div class="info-block">
|
<t-descriptions :title="$t('pages.detailBase.baseInfo.title')">
|
||||||
<div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item">
|
<t-descriptions-item v-for="(item, index) in BASE_INFO_DATA" :key="index" :label="item.name">
|
||||||
<h1>{{ item.name }}</h1>
|
|
||||||
<span
|
<span
|
||||||
:class="{
|
:class="{
|
||||||
['inProgress']: item.type && item.type.value === 'inProgress',
|
['inProgress']: item.type && item.type.value === 'inProgress',
|
||||||
|
@ -13,8 +12,8 @@
|
||||||
<i v-if="item.type && item.type.key === 'contractStatus'" />
|
<i v-if="item.type && item.type.key === 'contractStatus'" />
|
||||||
{{ item.value }}
|
{{ item.value }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</t-descriptions-item>
|
||||||
</div>
|
</t-descriptions>
|
||||||
</t-card>
|
</t-card>
|
||||||
|
|
||||||
<t-card :title="$t('pages.detailBase.changelog.title')" class="container-base-margin-top" :bordered="false">
|
<t-card :title="$t('pages.detailBase.changelog.title')" class="container-base-margin-top" :bordered="false">
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
:header-affixed-top="headerAffixedTop"
|
:header-affixed-top="headerAffixedTop"
|
||||||
@page-change="rehandlePageChange"
|
@page-change="rehandlePageChange"
|
||||||
@change="rehandleChange"
|
@change="rehandleChange"
|
||||||
@select-change="rehandleSelectChange"
|
@select-change="(value: number[]) => rehandleSelectChange(value)"
|
||||||
>
|
>
|
||||||
<template #status="{ row }">
|
<template #status="{ row }">
|
||||||
<t-tag v-if="row.status === CONTRACT_STATUS.FAIL" theme="danger" variant="light">
|
<t-tag v-if="row.status === CONTRACT_STATUS.FAIL" theme="danger" variant="light">
|
||||||
|
|
|
@ -74,7 +74,7 @@ const formVisible = ref(false);
|
||||||
const formData = ref({ ...INITIAL_DATA });
|
const formData = ref({ ...INITIAL_DATA });
|
||||||
const textareaValue = ref('');
|
const textareaValue = ref('');
|
||||||
|
|
||||||
const onSubmit = ({ validateResult, firstError }: SubmitContext<FormData>) => {
|
const onSubmit = ({ validateResult, firstError }: SubmitContext) => {
|
||||||
if (!firstError) {
|
if (!firstError) {
|
||||||
MessagePlugin.success('提交成功');
|
MessagePlugin.success('提交成功');
|
||||||
formVisible.value = false;
|
formVisible.value = false;
|
||||||
|
|
|
@ -15,16 +15,11 @@
|
||||||
<t-icon name="ellipsis" />
|
<t-icon name="ellipsis" />
|
||||||
</t-button>
|
</t-button>
|
||||||
</template>
|
</template>
|
||||||
<t-row class="content" justify="space-between">
|
<t-descriptions :column="4" item-layout="vertical">
|
||||||
<t-col v-for="(item, index) in USER_INFO_LIST" :key="index" class="contract" :span="item.span ?? 3">
|
<t-descriptions-item v-for="(item, index) in USER_INFO_LIST" :key="index" :label="$t(item.title)">
|
||||||
<div class="contract-title">
|
{{ item.content }}
|
||||||
{{ $t(item.title) }}
|
</t-descriptions-item>
|
||||||
</div>
|
</t-descriptions>
|
||||||
<div class="contract-detail">
|
|
||||||
{{ item.content }}
|
|
||||||
</div>
|
|
||||||
</t-col>
|
|
||||||
</t-row>
|
|
||||||
</t-card>
|
</t-card>
|
||||||
|
|
||||||
<t-card class="content-container" :bordered="false">
|
<t-card class="content-container" :bordered="false">
|
||||||
|
@ -185,4 +180,8 @@ watch(
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@import './index.less';
|
@import './index.less';
|
||||||
|
|
||||||
|
.t-descriptions {
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import uniq from 'lodash/uniq';
|
import uniq from 'lodash/uniq';
|
||||||
import { createRouter, createWebHistory, RouteRecordRaw, useRoute } from 'vue-router';
|
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
const env = import.meta.env.MODE || 'development';
|
const env = import.meta.env.MODE || 'development';
|
||||||
|
|
||||||
|
@ -59,7 +59,8 @@ export const getRoutesExpanded = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getActive = (maxLevel = 3): string => {
|
export const getActive = (maxLevel = 3): string => {
|
||||||
const route = useRoute();
|
// 非组件内调用必须通过Router实例获取当前路由
|
||||||
|
const route = router.currentRoute.value;
|
||||||
|
|
||||||
if (!route.path) {
|
if (!route.path) {
|
||||||
return '';
|
return '';
|
||||||
|
|
|
@ -2,15 +2,16 @@ import keys from 'lodash/keys';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { Color } from 'tvision-color';
|
import { Color } from 'tvision-color';
|
||||||
|
|
||||||
import { DARK_CHART_COLORS, LIGHT_CHART_COLORS } from '@/config/color';
|
import { DARK_CHART_COLORS, LIGHT_CHART_COLORS, TColorSeries } from '@/config/color';
|
||||||
import STYLE_CONFIG from '@/config/style';
|
import STYLE_CONFIG from '@/config/style';
|
||||||
import { store } from '@/store';
|
import { store } from '@/store';
|
||||||
|
import { ModeType } from '@/types/interface';
|
||||||
import { generateColorMap, insertThemeStylesheet } from '@/utils/color';
|
import { generateColorMap, insertThemeStylesheet } from '@/utils/color';
|
||||||
|
|
||||||
const state = {
|
const state: Record<string, any> = {
|
||||||
...STYLE_CONFIG,
|
...STYLE_CONFIG,
|
||||||
showSettingPanel: false,
|
showSettingPanel: false,
|
||||||
colorList: {},
|
colorList: {} as TColorSeries,
|
||||||
chartColors: LIGHT_CHART_COLORS,
|
chartColors: LIGHT_CHART_COLORS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ export const useSettingStore = defineStore('setting', {
|
||||||
showSidebar: (state) => state.layout !== 'top',
|
showSidebar: (state) => state.layout !== 'top',
|
||||||
showSidebarLogo: (state) => state.layout === 'side',
|
showSidebarLogo: (state) => state.layout === 'side',
|
||||||
showHeaderLogo: (state) => state.layout !== 'side',
|
showHeaderLogo: (state) => state.layout !== 'side',
|
||||||
displayMode: (state): 'dark' | 'light' => {
|
displayMode: (state): ModeType => {
|
||||||
if (state.mode === 'auto') {
|
if (state.mode === 'auto') {
|
||||||
const media = window.matchMedia('(prefers-color-scheme:dark)');
|
const media = window.matchMedia('(prefers-color-scheme:dark)');
|
||||||
if (media.matches) {
|
if (media.matches) {
|
||||||
|
@ -31,20 +32,18 @@ export const useSettingStore = defineStore('setting', {
|
||||||
}
|
}
|
||||||
return 'light';
|
return 'light';
|
||||||
}
|
}
|
||||||
return state.mode as 'dark' | 'light';
|
return state.mode as ModeType;
|
||||||
|
},
|
||||||
|
displaySideMode: (state): ModeType => {
|
||||||
|
return state.sideMode as ModeType;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async changeMode(mode: 'dark' | 'light' | 'auto') {
|
async changeMode(mode: ModeType | 'auto') {
|
||||||
let theme = mode;
|
let theme = mode;
|
||||||
|
|
||||||
if (mode === 'auto') {
|
if (mode === 'auto') {
|
||||||
const media = window.matchMedia('(prefers-color-scheme:dark)');
|
theme = this.getMediaColor();
|
||||||
if (media.matches) {
|
|
||||||
theme = 'dark';
|
|
||||||
} else {
|
|
||||||
theme = 'light';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const isDarkMode = theme === 'dark';
|
const isDarkMode = theme === 'dark';
|
||||||
|
|
||||||
|
@ -52,6 +51,19 @@ export const useSettingStore = defineStore('setting', {
|
||||||
|
|
||||||
this.chartColors = isDarkMode ? DARK_CHART_COLORS : LIGHT_CHART_COLORS;
|
this.chartColors = isDarkMode ? DARK_CHART_COLORS : LIGHT_CHART_COLORS;
|
||||||
},
|
},
|
||||||
|
async changeSideMode(mode: ModeType) {
|
||||||
|
const isDarkMode = mode === 'dark';
|
||||||
|
|
||||||
|
document.documentElement.setAttribute('side-mode', isDarkMode ? 'dark' : '');
|
||||||
|
},
|
||||||
|
getMediaColor() {
|
||||||
|
const media = window.matchMedia('(prefers-color-scheme:dark)');
|
||||||
|
|
||||||
|
if (media.matches) {
|
||||||
|
return 'dark';
|
||||||
|
}
|
||||||
|
return 'light';
|
||||||
|
},
|
||||||
changeBrandTheme(brandTheme: string) {
|
changeBrandTheme(brandTheme: string) {
|
||||||
const mode = this.displayMode;
|
const mode = this.displayMode;
|
||||||
// 以主题色加显示模式作为键
|
// 以主题色加显示模式作为键
|
||||||
|
@ -64,20 +76,23 @@ export const useSettingStore = defineStore('setting', {
|
||||||
step: 10,
|
step: 10,
|
||||||
remainInput: false, // 是否保留输入 不保留会矫正不合适的主题色
|
remainInput: false, // 是否保留输入 不保留会矫正不合适的主题色
|
||||||
});
|
});
|
||||||
colorMap = generateColorMap(brandTheme, newPalette, mode as 'light' | 'dark', brandColorIndex);
|
colorMap = generateColorMap(brandTheme, newPalette, mode, brandColorIndex);
|
||||||
this.colorList[colorKey] = colorMap;
|
this.colorList[colorKey] = colorMap;
|
||||||
}
|
}
|
||||||
// TODO 需要解决不停切换时有反复插入 style 的问题
|
// TODO 需要解决不停切换时有反复插入 style 的问题
|
||||||
insertThemeStylesheet(brandTheme, colorMap, mode as 'light' | 'dark');
|
insertThemeStylesheet(brandTheme, colorMap, mode);
|
||||||
document.documentElement.setAttribute('theme-color', brandTheme);
|
document.documentElement.setAttribute('theme-color', brandTheme);
|
||||||
},
|
},
|
||||||
updateConfig(payload: Partial<TState>) {
|
updateConfig(payload: Partial<TState>) {
|
||||||
for (const key in payload) {
|
for (const key in payload) {
|
||||||
if (payload[key as TStateKey] !== undefined) {
|
if (payload[key as TStateKey] !== undefined) {
|
||||||
this[key] = payload[key as TStateKey];
|
this[key as TStateKey] = payload[key as TStateKey];
|
||||||
}
|
}
|
||||||
if (key === 'mode') {
|
if (key === 'mode') {
|
||||||
this.changeMode(payload[key]);
|
this.changeMode(payload[key] as ModeType);
|
||||||
|
}
|
||||||
|
if (key === 'sideMode') {
|
||||||
|
this.changeSideMode(payload[key] as ModeType);
|
||||||
}
|
}
|
||||||
if (key === 'brandTheme') {
|
if (key === 'brandTheme') {
|
||||||
this.changeBrandTheme(payload[key]);
|
this.changeBrandTheme(payload[key]);
|
||||||
|
|
|
@ -163,7 +163,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&-logo-tdesign-logo {
|
&-logo-tdesign-logo {
|
||||||
padding: 0 var(--td-comp-paddingLR-xl);
|
margin-right: var(--td-comp-margin-xxxl);
|
||||||
height: var(--td-comp-size-s);
|
height: var(--td-comp-size-s);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
color: var(--td-text-color-primary);
|
color: var(--td-text-color-primary);
|
||||||
|
@ -176,6 +176,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-side-nav-dark {
|
||||||
|
color: var(--td-font-white-1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
&-side-nav-placeholder {
|
&-side-nav-placeholder {
|
||||||
flex: 1 1 232px;
|
flex: 1 1 232px;
|
||||||
min-width: 232px;
|
min-width: 232px;
|
||||||
|
|
10
src/types/interface.d.ts
vendored
10
src/types/interface.d.ts
vendored
|
@ -1,8 +1,6 @@
|
||||||
import type { TabValue } from 'tdesign-vue-next';
|
import type { TabValue } from 'tdesign-vue-next';
|
||||||
import { LocationQueryRaw, RouteRecordName } from 'vue-router';
|
import { LocationQueryRaw, RouteRecordName } from 'vue-router';
|
||||||
|
|
||||||
import STYLE_CONFIG from '@/config/style';
|
|
||||||
|
|
||||||
export interface RouteMeta {
|
export interface RouteMeta {
|
||||||
title?: string | Record<string, string>;
|
title?: string | Record<string, string>;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
|
@ -32,14 +30,6 @@ export interface MenuRoute {
|
||||||
|
|
||||||
export type ModeType = 'dark' | 'light';
|
export type ModeType = 'dark' | 'light';
|
||||||
|
|
||||||
export type SettingType = typeof STYLE_CONFIG;
|
|
||||||
|
|
||||||
export type ClassName = { [className: string]: any } | ClassName[] | string;
|
|
||||||
|
|
||||||
export type CommonObjType = {
|
|
||||||
[key: string]: string | number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface UserInfo {
|
export interface UserInfo {
|
||||||
name: string;
|
name: string;
|
||||||
roles: string[];
|
roles: string[];
|
||||||
|
|
|
@ -3,6 +3,7 @@ import trim from 'lodash/trim';
|
||||||
import { Color } from 'tvision-color';
|
import { Color } from 'tvision-color';
|
||||||
|
|
||||||
import { TColorToken } from '@/config/color';
|
import { TColorToken } from '@/config/color';
|
||||||
|
import { ModeType } from '@/types/interface';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 依据主题类型获取颜色
|
* 依据主题类型获取颜色
|
||||||
|
@ -58,12 +59,7 @@ export function changeChartsTheme(chartsList: echarts.EChartsType[]): void {
|
||||||
/**
|
/**
|
||||||
* 根据当前主题色、模式等情景 计算最后生成的色阶
|
* 根据当前主题色、模式等情景 计算最后生成的色阶
|
||||||
*/
|
*/
|
||||||
export function generateColorMap(
|
export function generateColorMap(theme: string, colorPalette: Array<string>, mode: ModeType, brandColorIdx: number) {
|
||||||
theme: string,
|
|
||||||
colorPalette: Array<string>,
|
|
||||||
mode: 'light' | 'dark',
|
|
||||||
brandColorIdx: number,
|
|
||||||
) {
|
|
||||||
const isDarkMode = mode === 'dark';
|
const isDarkMode = mode === 'dark';
|
||||||
|
|
||||||
if (isDarkMode) {
|
if (isDarkMode) {
|
||||||
|
@ -76,7 +72,7 @@ export function generateColorMap(
|
||||||
colorPalette[0] = `${colorPalette[brandColorIdx]}20`;
|
colorPalette[0] = `${colorPalette[brandColorIdx]}20`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const colorMap = {
|
const colorMap: TColorToken = {
|
||||||
'--td-brand-color': colorPalette[brandColorIdx], // 主题色
|
'--td-brand-color': colorPalette[brandColorIdx], // 主题色
|
||||||
'--td-brand-color-1': colorPalette[0], // light
|
'--td-brand-color-1': colorPalette[0], // light
|
||||||
'--td-brand-color-2': colorPalette[1], // focus
|
'--td-brand-color-2': colorPalette[1], // focus
|
||||||
|
@ -95,7 +91,7 @@ export function generateColorMap(
|
||||||
/**
|
/**
|
||||||
* 将生成的样式嵌入头部
|
* 将生成的样式嵌入头部
|
||||||
*/
|
*/
|
||||||
export function insertThemeStylesheet(theme: string, colorMap: TColorToken, mode: 'light' | 'dark') {
|
export function insertThemeStylesheet(theme: string, colorMap: TColorToken, mode: ModeType) {
|
||||||
const isDarkMode = mode === 'dark';
|
const isDarkMode = mode === 'dark';
|
||||||
const root = !isDarkMode ? `:root[theme-color='${theme}']` : `:root[theme-color='${theme}'][theme-mode='dark']`;
|
const root = !isDarkMode ? `:root[theme-color='${theme}']` : `:root[theme-color='${theme}'][theme-mode='dark']`;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module.exports = {
|
export default {
|
||||||
defaultSeverity: 'error',
|
defaultSeverity: 'error',
|
||||||
extends: ['stylelint-config-standard'],
|
extends: ['stylelint-config-standard'],
|
||||||
rules: {
|
rules: {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
|
"jsxImportSource": "vue",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
@ -16,7 +17,11 @@
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["src/*"]
|
"@/*": ["src/*"]
|
||||||
},
|
},
|
||||||
"noImplicitAny": true
|
"noImplicitAny": true,
|
||||||
|
"strictFunctionTypes": true,
|
||||||
|
"strictBindCallApply": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"alwaysStrict": true,
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"**/*.ts",
|
"**/*.ts",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user