fix: 修复全量类型检查报错

- 收敛可选配置字段并补齐默认值,消除 strict 模式报错

- 补充页面脚本类型定义,移除未使用变量与隐式 any

- 修复主题、表格、标签页等公共包类型边界
This commit is contained in:
2026-02-24 16:45:23 +08:00
parent 306b08d55a
commit 0bb4c884b0
14 changed files with 113 additions and 68 deletions

View File

@@ -92,7 +92,7 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
client, client,
doReAuthenticate, doReAuthenticate,
doRefreshToken, doRefreshToken,
enableRefreshToken: preferences.app.enableRefreshToken, enableRefreshToken: preferences.app.enableRefreshToken ?? false,
formatToken, formatToken,
}), }),
); );

View File

@@ -22,7 +22,7 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) {
IFrameView, IFrameView,
}; };
return await generateAccessible(preferences.app.accessMode, { return await generateAccessible(preferences.app.accessMode ?? 'frontend', {
...options, ...options,
fetchMenuListAsync: async () => { fetchMenuListAsync: async () => {
ElMessage({ ElMessage({

View File

@@ -54,11 +54,9 @@ export const useAuthStore = defineStore('auth', () => {
if (accessStore.loginExpired) { if (accessStore.loginExpired) {
accessStore.setLoginExpired(false); accessStore.setLoginExpired(false);
} else { } else {
onSuccess const homePath =
? await onSuccess?.() userInfo.homePath || preferences.app.defaultHomePath || '/';
: await router.push( onSuccess ? await onSuccess?.() : await router.push(homePath);
userInfo.homePath || preferences.app.defaultHomePath,
);
} }
if (userInfo?.nickname) { if (userInfo?.nickname) {

View File

@@ -8,7 +8,6 @@ import { useAppConfig } from '@easyflow/hooks';
import { $t } from '@easyflow/locales'; import { $t } from '@easyflow/locales';
import { preferences } from '@easyflow/preferences'; import { preferences } from '@easyflow/preferences';
import { api } from '#/api/request';
import { useAuthStore } from '#/store'; import { useAuthStore } from '#/store';
defineOptions({ name: 'Login' }); defineOptions({ name: 'Login' });
@@ -18,8 +17,6 @@ const authStore = useAuthStore();
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
type PlatformType = 'ding_talk' | 'wx_web';
const title = computed(() => preferences.auth.welcomeBack); const title = computed(() => preferences.auth.welcomeBack);
const subTitle = computed(() => preferences.auth.loginSubtitle); const subTitle = computed(() => preferences.auth.loginSubtitle);
const formSchema = computed((): EasyFlowFormSchema[] => { const formSchema = computed((): EasyFlowFormSchema[] => {
@@ -91,14 +88,6 @@ function onSubmit(values: any) {
console.error('初始化tac失败', error); console.error('初始化tac失败', error);
}); });
} }
function getAuthUrl(platform: PlatformType) {
return api.get('/thirdAuth/getAuthUrl', {
params: {
platform,
},
});
}
</script> </script>
<template> <template>

View File

@@ -29,6 +29,26 @@ import AddPluginModal from '#/views/ai/plugin/AddPluginModal.vue';
import CategoryPluginModal from '#/views/ai/plugin/CategoryPluginModal.vue'; import CategoryPluginModal from '#/views/ai/plugin/CategoryPluginModal.vue';
const router = useRouter(); const router = useRouter();
interface PluginCategory {
id: string;
name: string;
}
interface PluginRecord {
id: string;
[key: string]: unknown;
}
interface HeaderActionEvent {
key?: string;
}
interface CategoryFormData {
id?: string;
name: string;
}
// 操作按钮配置 // 操作按钮配置
const actions: ActionButton[] = [ const actions: ActionButton[] = [
{ {
@@ -74,12 +94,12 @@ const actions: ActionButton[] = [
}, },
}, },
]; ];
const categoryList = ref([]); const categoryList = ref<PluginCategory[]>([]);
const controlBtns = [ const controlBtns = [
{ {
icon: Edit, icon: Edit,
label: $t('button.edit'), label: $t('button.edit'),
onClick(row) { onClick(row: PluginCategory) {
formData.value.name = row.name; formData.value.name = row.name;
formData.value.id = row.id; formData.value.id = row.id;
isEdit.value = true; isEdit.value = true;
@@ -90,7 +110,7 @@ const controlBtns = [
type: 'danger', type: 'danger',
icon: Delete, icon: Delete,
label: $t('button.delete'), label: $t('button.delete'),
onClick(row) { onClick(row: PluginCategory) {
handleDeleteCategory(row); handleDeleteCategory(row);
}, },
}, },
@@ -106,9 +126,12 @@ const footerButton = {
const getPluginCategoryList = async () => { const getPluginCategoryList = async () => {
return api.get('/api/v1/pluginCategory/list').then((res) => { return api.get('/api/v1/pluginCategory/list').then((res) => {
if (res.errorCode === 0) { if (res.errorCode === 0) {
const serverCategories = Array.isArray(res.data)
? (res.data as PluginCategory[])
: [];
categoryList.value = [ categoryList.value = [
{ id: '0', name: $t('common.allCategories') }, { id: '0', name: $t('common.allCategories') },
...res.data, ...serverCategories,
]; ];
} }
}); });
@@ -116,7 +139,7 @@ const getPluginCategoryList = async () => {
onMounted(() => { onMounted(() => {
getPluginCategoryList(); getPluginCategoryList();
}); });
const handleDelete = (item) => { const handleDelete = (item: PluginRecord) => {
ElMessageBox.confirm($t('message.deleteAlert'), $t('message.noticeTitle'), { ElMessageBox.confirm($t('message.deleteAlert'), $t('message.noticeTitle'), {
confirmButtonText: $t('message.ok'), confirmButtonText: $t('message.ok'),
cancelButtonText: $t('message.cancel'), cancelButtonText: $t('message.cancel'),
@@ -148,7 +171,7 @@ const headerButtons = [
const pluginCategoryId = ref('0'); const pluginCategoryId = ref('0');
const dialogVisible = ref(false); // 弹窗显隐 const dialogVisible = ref(false); // 弹窗显隐
const isEdit = ref(false); // 是否为编辑模式 const isEdit = ref(false); // 是否为编辑模式
const formData = ref({ name: '', id: '' }); const formData = ref<CategoryFormData>({ name: '', id: '' });
const handleSubmit = () => { const handleSubmit = () => {
// 触发对应事件,传递表单数据 // 触发对应事件,传递表单数据
@@ -160,7 +183,7 @@ const handleSubmit = () => {
// 提交后关闭弹窗 // 提交后关闭弹窗
dialogVisible.value = false; dialogVisible.value = false;
}; };
const handleButtonClick = (event, _item) => { const handleButtonClick = (event: HeaderActionEvent, _item: unknown) => {
switch (event.key) { switch (event.key) {
case 'add': { case 'add': {
aiPluginModalRef.value.openDialog({}); aiPluginModalRef.value.openDialog({});
@@ -168,10 +191,10 @@ const handleButtonClick = (event, _item) => {
} }
} }
}; };
const handleSearch = (params) => { const handleSearch = (params?: string) => {
pageDataRef.value.setQuery({ title: params, isQueryOr: true }); pageDataRef.value.setQuery({ title: params ?? '', isQueryOr: true });
}; };
const handleEditCategory = (params) => { const handleEditCategory = (params: CategoryFormData) => {
api api
.post('/api/v1/pluginCategory/update', { .post('/api/v1/pluginCategory/update', {
id: params.id, id: params.id,
@@ -184,7 +207,7 @@ const handleEditCategory = (params) => {
} }
}); });
}; };
const handleAddCategory = (params) => { const handleAddCategory = (params: CategoryFormData) => {
api.post('/api/v1/pluginCategory/save', { name: params.name }).then((res) => { api.post('/api/v1/pluginCategory/save', { name: params.name }).then((res) => {
if (res.errorCode === 0) { if (res.errorCode === 0) {
getPluginCategoryList(); getPluginCategoryList();
@@ -192,7 +215,7 @@ const handleAddCategory = (params) => {
} }
}); });
}; };
const handleDeleteCategory = (params) => { const handleDeleteCategory = (params: PluginCategory) => {
api api
.get(`/api/v1/pluginCategory/doRemoveCategory?id=${params.id}`) .get(`/api/v1/pluginCategory/doRemoveCategory?id=${params.id}`)
.then((res) => { .then((res) => {
@@ -202,7 +225,7 @@ const handleDeleteCategory = (params) => {
} }
}); });
}; };
const handleClickCategory = (item) => { const handleClickCategory = (item: PluginCategory) => {
pageDataRef.value.setQuery({ category: item.id }); pageDataRef.value.setQuery({ category: item.id });
}; };
</script> </script>

View File

@@ -29,6 +29,7 @@ const pageDataRef = ref();
const saveDialog = ref(); const saveDialog = ref();
const formInline = ref({ const formInline = ref({
id: '', id: '',
title: '',
}); });
function search(formEl: FormInstance | undefined) { function search(formEl: FormInstance | undefined) {
formEl?.validate((valid) => { formEl?.validate((valid) => {

View File

@@ -17,17 +17,47 @@ import {
import { api } from '#/api/request.js'; import { api } from '#/api/request.js';
import providerList from '#/views/ai/model/modelUtils/providerList.json'; import providerList from '#/views/ai/model/modelUtils/providerList.json';
const providerOptions = interface ProviderOptionExtra {
ref<Array<{ label: string; options: any; value: string }>>(providerList); chatPath?: string;
const brands = ref([]); llmEndpoint?: string;
const llmOptions = ref([]); }
interface ProviderOption {
label: string;
options?: ProviderOptionExtra;
value: string;
}
interface ModelProvider {
key: string;
options?: ProviderOptionExtra;
title: string;
}
interface LlmOption {
extra: Map<string, string | undefined>;
label: string;
value: string;
}
interface SettingsEntity {
chatgpt_api_key: string;
chatgpt_chatPath: string;
chatgpt_endpoint: string;
chatgpt_model_name: string;
model_of_chat: string;
}
const providerOptions = ref<ProviderOption[]>(providerList as ProviderOption[]);
const brands = ref<ModelProvider[]>([]);
const llmOptions = ref<LlmOption[]>([]);
// 获取品牌接口数据 // 获取品牌接口数据
function getBrands() { function getBrands() {
api.get('/api/v1/modelProvider/list').then((res) => { api.get('/api/v1/modelProvider/list').then((res) => {
if (res.errorCode === 0) { if (res.errorCode === 0) {
brands.value = res.data; brands.value = (res.data ?? []) as ModelProvider[];
llmOptions.value = formatLlmList(res.data); llmOptions.value = formatLlmList(brands.value);
} }
}); });
} }
@@ -47,7 +77,7 @@ onMounted(() => {
getBrands(); getBrands();
}); });
const entity = ref({ const entity = ref<SettingsEntity>({
model_of_chat: '', model_of_chat: '',
chatgpt_api_key: '', chatgpt_api_key: '',
chatgpt_chatPath: '', chatgpt_chatPath: '',
@@ -55,7 +85,7 @@ const entity = ref({
chatgpt_model_name: '', chatgpt_model_name: '',
}); });
function formatLlmList(data) { function formatLlmList(data: ModelProvider[]): LlmOption[] {
return data.map((item) => { return data.map((item) => {
const extra = new Map([ const extra = new Map([
['chatPath', item.options?.chatPath], ['chatPath', item.options?.chatPath],
@@ -68,10 +98,10 @@ function formatLlmList(data) {
}; };
}); });
} }
function handleChangeModel(value) { function handleChangeModel(value: string) {
const extra = providerList.find((item) => item.value === value); const extra = providerList.find((item) => item.value === value);
entity.value.chatgpt_chatPath = extra.options.chatPath; entity.value.chatgpt_chatPath = extra?.options?.chatPath ?? '';
entity.value.chatgpt_endpoint = extra.options.llmEndpoint; entity.value.chatgpt_endpoint = extra?.options?.llmEndpoint ?? '';
} }
function handleSave() { function handleSave() {
api.post('/api/v1/sysOption/save', entity.value).then((res) => { api.post('/api/v1/sysOption/save', entity.value).then((res) => {

View File

@@ -29,8 +29,9 @@ function updateCSSVariables(preferences: Preferences) {
// html 设置 data-theme=[builtinType] // html 设置 data-theme=[builtinType]
if (Reflect.has(theme, 'builtinType')) { if (Reflect.has(theme, 'builtinType')) {
const rootTheme = root.dataset.theme; const rootTheme = root.dataset.theme;
if (rootTheme !== builtinType) { const resolvedBuiltinType = builtinType ?? '';
root.dataset.theme = builtinType; if (rootTheme !== resolvedBuiltinType) {
root.dataset.theme = resolvedBuiltinType;
} }
} }
@@ -39,7 +40,7 @@ function updateCSSVariables(preferences: Preferences) {
(item) => item.type === builtinType, (item) => item.type === builtinType,
); );
let builtinTypeColorPrimary: string | undefined = ''; let builtinTypeColorPrimary: string | undefined;
if (currentBuiltType) { if (currentBuiltType) {
const isDark = isDarkTheme(preferences.theme.mode); const isDark = isDarkTheme(preferences.theme.mode);
@@ -78,12 +79,16 @@ function updateMainColorVariables(preference: Preferences) {
} }
const { colorDestructive, colorPrimary, colorSuccess, colorWarning } = const { colorDestructive, colorPrimary, colorSuccess, colorWarning } =
preference.theme; preference.theme;
const resolvedColorPrimary = colorPrimary ?? 'hsl(216 100% 50%)';
const resolvedColorWarning = colorWarning ?? 'hsl(42 84% 61%)';
const resolvedColorSuccess = colorSuccess ?? 'hsl(144 57% 58%)';
const resolvedColorDestructive = colorDestructive ?? 'hsl(348 100% 61%)';
const colorVariables = generatorColorVariables([ const colorVariables = generatorColorVariables([
{ color: colorPrimary, name: 'primary' }, { color: resolvedColorPrimary, name: 'primary' },
{ alias: 'warning', color: colorWarning, name: 'yellow' }, { alias: 'warning', color: resolvedColorWarning, name: 'yellow' },
{ alias: 'success', color: colorSuccess, name: 'green' }, { alias: 'success', color: resolvedColorSuccess, name: 'green' },
{ alias: 'destructive', color: colorDestructive, name: 'red' }, { alias: 'destructive', color: resolvedColorDestructive, name: 'red' },
]); ]);
// 要设置的 CSS 变量映射 // 要设置的 CSS 变量映射
@@ -105,7 +110,7 @@ function updateMainColorVariables(preference: Preferences) {
executeUpdateCSSVariables(colorVariables); executeUpdateCSSVariables(colorVariables);
} }
function isDarkTheme(theme: string) { function isDarkTheme(theme?: string) {
let dark = theme === 'dark'; let dark = theme === 'dark';
if (theme === 'auto') { if (theme === 'auto') {
dark = window.matchMedia('(prefers-color-scheme: dark)').matches; dark = window.matchMedia('(prefers-color-scheme: dark)').matches;

View File

@@ -3,8 +3,8 @@ import type { Props } from './types';
import { preferences } from '@easyflow-core/preferences'; import { preferences } from '@easyflow-core/preferences';
import { import {
EasyFlowAvatar,
Card, Card,
EasyFlowAvatar,
Tabs, Tabs,
TabsList, TabsList,
TabsTrigger, TabsTrigger,
@@ -29,14 +29,14 @@ const tabsValue = defineModel<string>('modelValue');
<Card class="w-[200px]"> <Card class="w-[200px]">
<div class="mt-4 flex h-40 flex-col items-center justify-center gap-4"> <div class="mt-4 flex h-40 flex-col items-center justify-center gap-4">
<EasyFlowAvatar <EasyFlowAvatar
:src="userInfo?.avatar ?? preferences.app.defaultAvatar" :src="userInfo?.avatar ?? preferences.app.defaultAvatar ?? ''"
class="size-20" class="size-20"
/> />
<span class="text-lg font-semibold"> <span class="text-lg font-semibold">
{{ userInfo?.realName ?? '' }} {{ (userInfo as any)?.realName ?? userInfo?.nickname ?? '' }}
</span> </span>
<span class="text-foreground/80 text-sm"> <span class="text-foreground/80 text-sm">
{{ userInfo?.username ?? '' }} {{ (userInfo as any)?.username ?? userInfo?.loginName ?? '' }}
</span> </span>
</div> </div>
<!-- <Separator class="my-4" /> --> <!-- <Separator class="my-4" /> -->

View File

@@ -159,7 +159,7 @@ function autoCollapseMenuByRouteMeta(route: RouteLocationNormalizedLoaded) {
// 只在双列模式下生效 // 只在双列模式下生效
if ( if (
['header-mixed-nav', 'sidebar-mixed-nav'].includes( ['header-mixed-nav', 'sidebar-mixed-nav'].includes(
preferences.app.layout, preferences.app.layout ?? '',
) && ) &&
route.meta && route.meta &&
route.meta.hideInMenu route.meta.hideInMenu
@@ -259,9 +259,9 @@ const headerSlots = computed(() => {
:class="logoClass" :class="logoClass"
:collapsed="logoCollapsed" :collapsed="logoCollapsed"
:src="preferences.logo.source" :src="preferences.logo.source"
:src-dark="preferences.logo.sourceDark" :src-dark="preferences.logo.sourceDark ?? preferences.logo.source ?? ''"
:src-mini="preferences.logo.sourceMini" :src-mini="preferences.logo.sourceMini ?? preferences.logo.source ?? ''"
:text="preferences.app.name" :text="preferences.app.name ?? ''"
:theme="showHeaderNav ? headerTheme : theme" :theme="showHeaderNav ? headerTheme : theme"
@click="clickLogo" @click="clickLogo"
> >
@@ -353,9 +353,9 @@ const headerSlots = computed(() => {
v-if="preferences.logo.enable" v-if="preferences.logo.enable"
:fit="preferences.logo.fit" :fit="preferences.logo.fit"
:src="preferences.logo.source" :src="preferences.logo.source"
:src-dark="preferences.logo.sourceDark" :src-dark="preferences.logo.sourceDark ?? preferences.logo.source ?? ''"
:src-mini="preferences.logo.sourceMini" :src-mini="preferences.logo.sourceMini ?? preferences.logo.source ?? ''"
:text="preferences.app.name" :text="preferences.app.name ?? ''"
:theme="theme" :theme="theme"
> >
<template v-if="$slots['logo-text']" #text> <template v-if="$slots['logo-text']" #text>

View File

@@ -235,7 +235,7 @@ async function handleReset() {
return; return;
} }
resetPreferences(); resetPreferences();
await loadLocaleMessages(preferences.app.locale); await loadLocaleMessages(preferences.app.locale ?? 'zh-CN');
} }
</script> </script>

View File

@@ -22,8 +22,6 @@ import echarts from './echarts';
type EchartsUIType = typeof EchartsUI | undefined; type EchartsUIType = typeof EchartsUI | undefined;
type EchartsThemeType = 'dark' | 'light' | null;
function useEcharts(chartRef: Ref<EchartsUIType>) { function useEcharts(chartRef: Ref<EchartsUIType>) {
let chartInstance: echarts.ECharts | null = null; let chartInstance: echarts.ECharts | null = null;
let cacheOptions: EChartsOption = {}; let cacheOptions: EChartsOption = {};
@@ -57,7 +55,7 @@ function useEcharts(chartRef: Ref<EchartsUIType>) {
}; };
}); });
const initCharts = (t?: EchartsThemeType) => { const initCharts = () => {
const el = chartRef?.value?.$el; const el = chartRef?.value?.$el;
if (!el) { if (!el) {
return; return;

View File

@@ -116,9 +116,10 @@ export function setupEasyFlowVxeTable(setupOptions: SetupVxeTable) {
watch( watch(
[() => isDark.value, () => locale.value], [() => isDark.value, () => locale.value],
([isDarkValue, localeValue]) => { ([isDarkValue, localeValue]) => {
const resolvedLocale = (localeValue ?? 'zh-CN') as keyof typeof localMap;
VxeUI.setTheme(isDarkValue ? 'dark' : 'light'); VxeUI.setTheme(isDarkValue ? 'dark' : 'light');
VxeUI.setI18n(localeValue, localMap[localeValue]); VxeUI.setI18n(resolvedLocale, localMap[resolvedLocale]);
VxeUI.setLanguage(localeValue); VxeUI.setLanguage(resolvedLocale);
}, },
{ {
immediate: true, immediate: true,

View File

@@ -120,7 +120,7 @@ export const useTabbarStore = defineStore('core-tabbar', {
}); });
if (tabIndex === -1) { if (tabIndex === -1) {
const maxCount = preferences.tabbar.maxCount; const maxCount = preferences.tabbar.maxCount ?? 0;
// 获取动态路由打开数,超过 0 即代表需要控制打开数 // 获取动态路由打开数,超过 0 即代表需要控制打开数
const maxNumOfOpenTab = (routeTab?.meta?.maxNumOfOpenTab ?? const maxNumOfOpenTab = (routeTab?.meta?.maxNumOfOpenTab ??
-1) as number; -1) as number;