chore(frontend): introduce prettier + eslint and prune unused code
Backend CI / Backend (push) Has been cancelled
Frontend CI / Frontend (push) Failing after 1m39s

- Add Prettier 3 with prettier-plugin-organize-imports (sorts/removes unused imports)
- Add ESLint 10 flat config with typescript-eslint + eslint-plugin-vue + eslint-config-prettier
- Add root scripts: format, format:check, lint, lint:fix
- Reformat 257 files across admin-web, ops-web, desktop-client, packages
- Remove unused locals/exports flagged by --noUnusedLocals/--noUnusedParameters
- Fix duplicate localTabLabel key, surrogate-pair regex u-flag, NBSP literal in regex
- Skip server/ (Go) and apps/browser-extension/ (deprecated per ADR)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 20:39:09 +08:00
parent 21c7892ee4
commit 162abdc97c
258 changed files with 42261 additions and 37556 deletions
+122 -88
View File
@@ -5,72 +5,92 @@ import {
PauseCircleOutlined,
PlayCircleOutlined,
PlusOutlined,
} from "@ant-design/icons-vue";
import { useMutation, useQuery, useQueryClient } from "@tanstack/vue-query";
import { message, type TableColumnsType } from "ant-design-vue";
import type { PromptRule, PromptRuleGroup } from "@geo/shared-types";
import { computed, reactive, ref, watch } from "vue";
import { useI18n } from "vue-i18n";
} from '@ant-design/icons-vue'
import type { PromptRule, PromptRuleGroup } from '@geo/shared-types'
import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'
import { message, type TableColumnsType } from 'ant-design-vue'
import { computed, reactive, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import PromptRuleModal from "@/components/PromptRuleModal.vue";
import { promptRulesApi } from "@/lib/api";
import { formatDateTime } from "@/lib/display";
import { formatError } from "@/lib/errors";
import PromptRuleModal from '@/components/PromptRuleModal.vue'
import { promptRulesApi } from '@/lib/api'
import { formatDateTime } from '@/lib/display'
import { formatError } from '@/lib/errors'
const queryClient = useQueryClient();
const { t } = useI18n();
const queryClient = useQueryClient()
const { t } = useI18n()
const selectedGroupId = ref<number | "all" | "ungrouped">("all");
const ruleModalOpen = ref(false);
const editingRule = ref<PromptRule | null>(null);
const groupModalOpen = ref(false);
const editingGroupId = ref<number | null>(null);
const groupForm = reactive({ name: "" });
const page = ref(1);
const pageSize = ref(20);
const selectedGroupId = ref<number | 'all' | 'ungrouped'>('all')
const ruleModalOpen = ref(false)
const editingRule = ref<PromptRule | null>(null)
const groupModalOpen = ref(false)
const editingGroupId = ref<number | null>(null)
const groupForm = reactive({ name: '' })
const page = ref(1)
const pageSize = ref(20)
const groupsQuery = useQuery({
queryKey: ["promptRules", "groups"],
queryKey: ['promptRules', 'groups'],
queryFn: () => promptRulesApi.listGroups(),
});
})
const ruleListParams = computed(() => {
const params: Record<string, unknown> = {
page: page.value,
page_size: pageSize.value,
};
if (selectedGroupId.value === "ungrouped") {
params.ungrouped = true;
} else if (selectedGroupId.value !== "all") {
params.group_id = selectedGroupId.value;
}
return params;
});
if (selectedGroupId.value === 'ungrouped') {
params.ungrouped = true
} else if (selectedGroupId.value !== 'all') {
params.group_id = selectedGroupId.value
}
return params
})
const rulesQuery = useQuery({
queryKey: computed(() => ["promptRules", "list", ruleListParams.value]),
queryKey: computed(() => ['promptRules', 'list', ruleListParams.value]),
queryFn: () => promptRulesApi.list(ruleListParams.value),
});
})
const columns = computed<TableColumnsType<PromptRule>>(() => [
{ title: t("custom.promptRule.name"), dataIndex: "name", key: "name", width: 160 },
{ title: t("custom.promptRule.content"), dataIndex: "prompt_content", key: "prompt_content", ellipsis: true },
{ title: t("custom.promptRule.scene"), dataIndex: "scene", key: "scene", width: 120 },
{ title: t("custom.promptRule.tone"), dataIndex: "default_tone", key: "default_tone", width: 100 },
{ title: t("custom.promptRule.wordCount"), dataIndex: "default_word_count", key: "default_word_count", width: 100 },
{ title: t("custom.promptRule.articleCount"), dataIndex: "article_count", key: "article_count", width: 100 },
{ title: t("custom.promptRule.status"), dataIndex: "status", key: "status", width: 100 },
{ title: t("common.createdAt"), dataIndex: "created_at", key: "created_at", width: 168 },
{ title: t("common.actions"), key: "actions", width: 140, fixed: "right", align: "right" },
]);
{ title: t('custom.promptRule.name'), dataIndex: 'name', key: 'name', width: 160 },
{
title: t('custom.promptRule.content'),
dataIndex: 'prompt_content',
key: 'prompt_content',
ellipsis: true,
},
{ title: t('custom.promptRule.scene'), dataIndex: 'scene', key: 'scene', width: 120 },
{
title: t('custom.promptRule.tone'),
dataIndex: 'default_tone',
key: 'default_tone',
width: 100,
},
{
title: t('custom.promptRule.wordCount'),
dataIndex: 'default_word_count',
key: 'default_word_count',
width: 100,
},
{
title: t('custom.promptRule.articleCount'),
dataIndex: 'article_count',
key: 'article_count',
width: 100,
},
{ title: t('custom.promptRule.status'), dataIndex: 'status', key: 'status', width: 100 },
{ title: t('common.createdAt'), dataIndex: 'created_at', key: 'created_at', width: 168 },
{ title: t('common.actions'), key: 'actions', width: 140, fixed: 'right', align: 'right' },
])
const groupMutations = {
create: useMutation({
mutationFn: () => promptRulesApi.createGroup({ name: groupForm.name.trim() }),
onSuccess: async () => {
message.success(t("custom.messages.groupCreated"));
groupModalOpen.value = false;
await queryClient.invalidateQueries({ queryKey: ["promptRules", "groups"] });
message.success(t('custom.messages.groupCreated'))
groupModalOpen.value = false
await queryClient.invalidateQueries({ queryKey: ['promptRules', 'groups'] })
},
onError: (error) => message.error(formatError(error)),
}),
@@ -78,77 +98,77 @@ const groupMutations = {
mutationFn: () =>
promptRulesApi.updateGroup(editingGroupId.value as number, { name: groupForm.name.trim() }),
onSuccess: async () => {
message.success(t("custom.messages.groupUpdated"));
groupModalOpen.value = false;
await queryClient.invalidateQueries({ queryKey: ["promptRules", "groups"] });
message.success(t('custom.messages.groupUpdated'))
groupModalOpen.value = false
await queryClient.invalidateQueries({ queryKey: ['promptRules', 'groups'] })
},
onError: (error) => message.error(formatError(error)),
}),
remove: useMutation({
mutationFn: (id: number) => promptRulesApi.removeGroup(id),
onSuccess: async () => {
message.success(t("custom.messages.groupDeleted"));
message.success(t('custom.messages.groupDeleted'))
if (selectedGroupId.value === editingGroupId.value) {
selectedGroupId.value = "all";
selectedGroupId.value = 'all'
}
await queryClient.invalidateQueries({ queryKey: ["promptRules"] });
await queryClient.invalidateQueries({ queryKey: ['promptRules'] })
},
onError: (error) => message.error(formatError(error)),
}),
};
}
const ruleMutations = {
remove: useMutation({
mutationFn: (id: number) => promptRulesApi.remove(id),
onSuccess: async () => {
message.success(t("custom.messages.ruleDeleted"));
await queryClient.invalidateQueries({ queryKey: ["promptRules"] });
message.success(t('custom.messages.ruleDeleted'))
await queryClient.invalidateQueries({ queryKey: ['promptRules'] })
},
onError: (error) => message.error(formatError(error)),
}),
toggleStatus: useMutation({
mutationFn: ({ id, status }: { id: number; status: "enabled" | "disabled" }) =>
mutationFn: ({ id, status }: { id: number; status: 'enabled' | 'disabled' }) =>
promptRulesApi.toggleStatus(id, { status }),
onSuccess: async (_data, variables) => {
message.success(
variables.status === "enabled"
? t("custom.messages.ruleEnabled")
: t("custom.messages.ruleDisabled"),
);
await queryClient.invalidateQueries({ queryKey: ["promptRules"] });
variables.status === 'enabled'
? t('custom.messages.ruleEnabled')
: t('custom.messages.ruleDisabled'),
)
await queryClient.invalidateQueries({ queryKey: ['promptRules'] })
},
onError: (error) => message.error(formatError(error)),
}),
};
}
function openGroupModal(group?: PromptRuleGroup): void {
editingGroupId.value = group?.id ?? null;
groupForm.name = group?.name ?? "";
groupModalOpen.value = true;
editingGroupId.value = group?.id ?? null
groupForm.name = group?.name ?? ''
groupModalOpen.value = true
}
async function submitGroup(): Promise<void> {
if (!groupForm.name.trim()) return;
if (!groupForm.name.trim()) return
if (editingGroupId.value) {
await groupMutations.update.mutateAsync();
await groupMutations.update.mutateAsync()
} else {
await groupMutations.create.mutateAsync();
await groupMutations.create.mutateAsync()
}
}
function openRuleModal(rule?: PromptRule): void {
editingRule.value = rule ?? null;
ruleModalOpen.value = true;
editingRule.value = rule ?? null
ruleModalOpen.value = true
}
function handleTableChange(nextPage: number, nextPageSize: number): void {
page.value = nextPage;
pageSize.value = nextPageSize;
page.value = nextPage
pageSize.value = nextPageSize
}
watch(selectedGroupId, () => {
page.value = 1;
});
page.value = 1
})
</script>
<template>
@@ -157,7 +177,7 @@ watch(selectedGroupId, () => {
<!-- Group sidebar -->
<aside class="prompt-rule-tab__sidebar">
<div class="prompt-rule-tab__sidebar-head">
<h4>{{ t("custom.group.title") }}</h4>
<h4>{{ t('custom.group.title') }}</h4>
<a-button type="text" size="small" @click="openGroupModal()">
<template #icon><PlusOutlined /></template>
</a-button>
@@ -169,7 +189,7 @@ watch(selectedGroupId, () => {
:class="{ 'prompt-rule-tab__group-item--active': selectedGroupId === 'all' }"
@click="selectedGroupId = 'all'"
>
<span>{{ t("custom.group.allRules") }}</span>
<span>{{ t('custom.group.allRules') }}</span>
</div>
<div
@@ -200,7 +220,7 @@ watch(selectedGroupId, () => {
:class="{ 'prompt-rule-tab__group-item--active': selectedGroupId === 'ungrouped' }"
@click="selectedGroupId = 'ungrouped'"
>
<span>{{ t("custom.promptRule.ungrouped") }}</span>
<span>{{ t('custom.promptRule.ungrouped') }}</span>
</div>
</div>
</aside>
@@ -209,11 +229,11 @@ watch(selectedGroupId, () => {
<div class="prompt-rule-tab__panel">
<div class="prompt-rule-tab__panel-head">
<span class="prompt-rule-tab__count">
{{ t("templates.list.count", { count: rulesQuery.data.value?.total ?? 0 }) }}
{{ t('templates.list.count', { count: rulesQuery.data.value?.total ?? 0 }) }}
</span>
<a-button type="primary" @click="openRuleModal()">
<template #icon><PlusOutlined /></template>
{{ t("common.create") }}
{{ t('common.create') }}
</a-button>
</div>
@@ -237,17 +257,21 @@ watch(selectedGroupId, () => {
<span class="prompt-rule-tab__content-cell">{{ record.prompt_content }}</span>
</template>
<template v-else-if="column.key === 'scene'">
{{ record.scene || "--" }}
{{ record.scene || '--' }}
</template>
<template v-else-if="column.key === 'default_tone'">
{{ record.default_tone || "--" }}
{{ record.default_tone || '--' }}
</template>
<template v-else-if="column.key === 'default_word_count'">
{{ record.default_word_count || "--" }}
{{ record.default_word_count || '--' }}
</template>
<template v-else-if="column.key === 'status'">
<a-tag :color="record.status === 'enabled' ? 'green' : 'default'">
{{ record.status === "enabled" ? t("custom.promptRule.enabled") : t("custom.promptRule.disabled") }}
{{
record.status === 'enabled'
? t('custom.promptRule.enabled')
: t('custom.promptRule.disabled')
}}
</a-tag>
</template>
<template v-else-if="column.key === 'created_at'">
@@ -267,7 +291,11 @@ watch(selectedGroupId, () => {
</a-button>
</a-tooltip>
<a-tooltip
:title="record.status === 'enabled' ? t('custom.promptRule.disabled') : t('custom.promptRule.enabled')"
:title="
record.status === 'enabled'
? t('custom.promptRule.disabled')
: t('custom.promptRule.enabled')
"
>
<a-button
type="text"
@@ -277,10 +305,12 @@ watch(selectedGroupId, () => {
'action-btn',
record.status === 'enabled' ? 'action-disable' : 'action-enable',
]"
@click="ruleMutations.toggleStatus.mutate({
id: record.id,
status: record.status === 'enabled' ? 'disabled' : 'enabled',
})"
@click="
ruleMutations.toggleStatus.mutate({
id: record.id,
status: record.status === 'enabled' ? 'disabled' : 'enabled',
})
"
>
<PauseCircleOutlined v-if="record.status === 'enabled'" />
<PlayCircleOutlined v-else />
@@ -311,7 +341,9 @@ watch(selectedGroupId, () => {
<a-modal
:open="groupModalOpen"
:title="editingGroupId ? t('custom.group.editTitle') : t('custom.group.createTitle')"
:confirm-loading="groupMutations.create.isPending.value || groupMutations.update.isPending.value"
:confirm-loading="
groupMutations.create.isPending.value || groupMutations.update.isPending.value
"
@ok="submitGroup"
@cancel="groupModalOpen = false"
>
@@ -369,7 +401,9 @@ watch(selectedGroupId, () => {
cursor: pointer;
font-size: 13px;
border: 1px solid transparent;
transition: background 0.2s, border-color 0.2s;
transition:
background 0.2s,
border-color 0.2s;
}
.prompt-rule-tab__group-item:hover {