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
@@ -1,60 +1,60 @@
<script setup lang="ts">
import { InfoCircleOutlined } from "@ant-design/icons-vue";
import { useMutation, useQuery, useQueryClient } from "@tanstack/vue-query";
import { message } from "ant-design-vue";
import type { PromptRule, PromptRuleGroup } from "@geo/shared-types";
import { computed, reactive, watch } from "vue";
import { useI18n } from "vue-i18n";
import { InfoCircleOutlined } from '@ant-design/icons-vue'
import type { PromptRule, PromptRuleGroup } from '@geo/shared-types'
import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'
import { message } from 'ant-design-vue'
import { computed, reactive, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import KnowledgeGroupSelect from "@/components/KnowledgeGroupSelect.vue";
import { promptRulesApi } from "@/lib/api";
import { formatError } from "@/lib/errors";
import KnowledgeGroupSelect from '@/components/KnowledgeGroupSelect.vue'
import { promptRulesApi } from '@/lib/api'
import { formatError } from '@/lib/errors'
const props = defineProps<{
open: boolean;
rule?: PromptRule | null;
}>();
open: boolean
rule?: PromptRule | null
}>()
const emit = defineEmits<{
"update:open": [value: boolean];
saved: [ruleId: number];
}>();
'update:open': [value: boolean]
saved: [ruleId: number]
}>()
const queryClient = useQueryClient();
const { t } = useI18n();
const queryClient = useQueryClient()
const { t } = useI18n()
const form = reactive({
name: "",
prompt_content: "",
scene: "",
default_tone: "",
name: '',
prompt_content: '',
scene: '',
default_tone: '',
default_word_count: undefined as number | undefined,
group_id: undefined as number | undefined,
knowledge_group_ids: [] as number[],
});
})
const groupsQuery = useQuery({
queryKey: ["promptRules", "groups"],
queryKey: ['promptRules', 'groups'],
queryFn: () => promptRulesApi.listGroups(),
});
})
watch(
() => props.open,
(open) => {
if (!open) {
return;
return
}
const rule = props.rule;
form.name = rule?.name ?? "";
form.prompt_content = rule?.prompt_content ?? "";
form.scene = rule?.scene ?? "";
form.default_tone = rule?.default_tone ?? "";
form.default_word_count = rule?.default_word_count ?? undefined;
form.group_id = rule?.group_id ?? undefined;
form.knowledge_group_ids = rule?.knowledge_group_ids ?? [];
const rule = props.rule
form.name = rule?.name ?? ''
form.prompt_content = rule?.prompt_content ?? ''
form.scene = rule?.scene ?? ''
form.default_tone = rule?.default_tone ?? ''
form.default_word_count = rule?.default_word_count ?? undefined
form.group_id = rule?.group_id ?? undefined
form.knowledge_group_ids = rule?.knowledge_group_ids ?? []
},
);
)
const createMutation = useMutation({
mutationFn: () =>
@@ -68,13 +68,13 @@ const createMutation = useMutation({
knowledge_group_ids: form.knowledge_group_ids,
}),
onSuccess: async (data) => {
message.success(t("custom.messages.ruleCreated"));
emit("saved", data.id);
emit("update:open", false);
await queryClient.invalidateQueries({ queryKey: ["promptRules"] });
message.success(t('custom.messages.ruleCreated'))
emit('saved', data.id)
emit('update:open', false)
await queryClient.invalidateQueries({ queryKey: ['promptRules'] })
},
onError: (error) => message.error(formatError(error)),
});
})
const updateMutation = useMutation({
mutationFn: () =>
@@ -88,41 +88,41 @@ const updateMutation = useMutation({
knowledge_group_ids: form.knowledge_group_ids,
}),
onSuccess: async () => {
message.success(t("custom.messages.ruleUpdated"));
message.success(t('custom.messages.ruleUpdated'))
if (props.rule?.id) {
emit("saved", props.rule.id);
emit('saved', props.rule.id)
}
emit("update:open", false);
await queryClient.invalidateQueries({ queryKey: ["promptRules"] });
emit('update:open', false)
await queryClient.invalidateQueries({ queryKey: ['promptRules'] })
},
onError: (error) => message.error(formatError(error)),
});
})
const submitLoading = computed(
() => createMutation.isPending.value || updateMutation.isPending.value,
);
)
const drawerTitle = computed(() =>
props.rule?.id ? t("custom.promptRule.editTitle") : t("custom.promptRule.createTitle"),
);
props.rule?.id ? t('custom.promptRule.editTitle') : t('custom.promptRule.createTitle'),
)
async function handleSubmit(): Promise<void> {
if (!form.name.trim()) {
message.warning(t("custom.messages.missingPromptName"));
return;
message.warning(t('custom.messages.missingPromptName'))
return
}
if (!form.prompt_content.trim()) {
message.warning(t("custom.messages.missingPromptContent"));
return;
message.warning(t('custom.messages.missingPromptContent'))
return
}
if (props.rule?.id) {
await updateMutation.mutateAsync();
return;
await updateMutation.mutateAsync()
return
}
await createMutation.mutateAsync();
await createMutation.mutateAsync()
}
</script>
@@ -139,7 +139,7 @@ async function handleSubmit(): Promise<void> {
<div class="prompt-rule-drawer__body">
<div class="prompt-rule-drawer__field">
<label class="prompt-rule-drawer__label prompt-rule-drawer__label--required">
{{ t("custom.promptRule.name") }}
{{ t('custom.promptRule.name') }}
</label>
<a-input
v-model:value="form.name"
@@ -151,7 +151,7 @@ async function handleSubmit(): Promise<void> {
<div class="prompt-rule-drawer__field">
<label class="prompt-rule-drawer__label prompt-rule-drawer__label--required">
{{ t("custom.promptRule.content") }}
{{ t('custom.promptRule.content') }}
</label>
<a-textarea
v-model:value="form.prompt_content"
@@ -161,34 +161,36 @@ async function handleSubmit(): Promise<void> {
</div>
<div class="prompt-rule-drawer__field">
<label class="prompt-rule-drawer__label">{{ t("custom.group.title") }}</label>
<label class="prompt-rule-drawer__label">{{ t('custom.group.title') }}</label>
<a-select
v-model:value="form.group_id"
size="large"
style="width: 100%"
:placeholder="t('custom.promptRule.groupPlaceholder')"
:options="(groupsQuery.data.value ?? []).map((group: PromptRuleGroup) => ({
label: group.name,
value: group.id,
}))"
:options="
(groupsQuery.data.value ?? []).map((group: PromptRuleGroup) => ({
label: group.name,
value: group.id,
}))
"
allow-clear
/>
</div>
<div class="prompt-rule-drawer__grid">
<div class="prompt-rule-drawer__field">
<label class="prompt-rule-drawer__label">{{ t("custom.promptRule.scene") }}</label>
<label class="prompt-rule-drawer__label">{{ t('custom.promptRule.scene') }}</label>
<a-input v-model:value="form.scene" size="large" />
</div>
<div class="prompt-rule-drawer__field">
<label class="prompt-rule-drawer__label">{{ t("custom.promptRule.tone") }}</label>
<label class="prompt-rule-drawer__label">{{ t('custom.promptRule.tone') }}</label>
<a-input v-model:value="form.default_tone" size="large" />
</div>
<div class="prompt-rule-drawer__field">
<label class="prompt-rule-drawer__label">
{{ t("custom.promptRule.wordCount") }}
{{ t('custom.promptRule.wordCount') }}
<a-tooltip :title="t('custom.promptRule.wordCountHint')">
<InfoCircleOutlined style="margin-left: 6px; color: #8c8c8c; cursor: help" />
</a-tooltip>
@@ -215,10 +217,10 @@ async function handleSubmit(): Promise<void> {
<template #footer>
<div class="prompt-rule-drawer__footer">
<a-button size="large" @click="emit('update:open', false)">
{{ t("common.cancel") }}
{{ t('common.cancel') }}
</a-button>
<a-button type="primary" size="large" :loading="submitLoading" @click="handleSubmit">
{{ t("common.confirm") }}
{{ t('common.confirm') }}
</a-button>
</div>
</template>
@@ -283,7 +285,7 @@ async function handleSubmit(): Promise<void> {
}
.prompt-rule-drawer__label--required::before {
content: "*";
content: '*';
margin-right: 4px;
color: #ff4d4f;
}