refactor(skills): remove subcategory field from skills
Drop subcategory column from database schema and update constraints Remove subcategory handling from backend queries and API endpoints Clean up frontend components and admin views to reflect the change
This commit is contained in:
@@ -23,8 +23,6 @@ Pokemon 可配置:
|
|||||||
|
|
||||||
特长 可配置:
|
特长 可配置:
|
||||||
- 名称
|
- 名称
|
||||||
- 二级分类(可空,用于给乱撒这类特长做二级分类)
|
|
||||||
Eg: 名称:乱撒,二级分类:棉花
|
|
||||||
|
|
||||||
喜欢的环境 可配置:
|
喜欢的环境 可配置:
|
||||||
- 名称
|
- 名称
|
||||||
|
|||||||
@@ -40,11 +40,12 @@ CREATE INDEX IF NOT EXISTS user_sessions_user_id_idx
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS skills (
|
CREATE TABLE IF NOT EXISTS skills (
|
||||||
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||||
name text NOT NULL,
|
name text NOT NULL UNIQUE
|
||||||
subcategory text,
|
|
||||||
UNIQUE (name, subcategory)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ALTER TABLE skills DROP COLUMN IF EXISTS subcategory;
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS skills_name_key ON skills(name);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS favorite_things (
|
CREATE TABLE IF NOT EXISTS favorite_things (
|
||||||
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||||
name text NOT NULL UNIQUE
|
name text NOT NULL UNIQUE
|
||||||
|
|||||||
@@ -19,9 +19,7 @@ type ConfigType =
|
|||||||
|
|
||||||
type ConfigDefinition = {
|
type ConfigDefinition = {
|
||||||
table: string;
|
table: string;
|
||||||
select: string;
|
|
||||||
order: string;
|
order: string;
|
||||||
hasSubcategory?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type IdQuantity = {
|
type IdQuantity = {
|
||||||
@@ -73,13 +71,13 @@ const timeOfDays = ['早晨', '中午', '傍晚', '晚上'];
|
|||||||
const weathers = ['晴天', '阴天', '雨天'];
|
const weathers = ['晴天', '阴天', '雨天'];
|
||||||
|
|
||||||
const configDefinitions: Record<ConfigType, ConfigDefinition> = {
|
const configDefinitions: Record<ConfigType, ConfigDefinition> = {
|
||||||
skills: { table: 'skills', select: 'id, name, subcategory', order: 'name, subcategory', hasSubcategory: true },
|
skills: { table: 'skills', order: 'name' },
|
||||||
environments: { table: 'environments', select: 'id, name', order: 'name' },
|
environments: { table: 'environments', order: 'name' },
|
||||||
'favorite-things': { table: 'favorite_things', select: 'id, name', order: 'name' },
|
'favorite-things': { table: 'favorite_things', order: 'name' },
|
||||||
'item-categories': { table: 'item_categories', select: 'id, name', order: 'name' },
|
'item-categories': { table: 'item_categories', order: 'name' },
|
||||||
'item-usages': { table: 'item_usages', select: 'id, name', order: 'name' },
|
'item-usages': { table: 'item_usages', order: 'name' },
|
||||||
'acquisition-methods': { table: 'acquisition_methods', select: 'id, name', order: 'name' },
|
'acquisition-methods': { table: 'acquisition_methods', order: 'name' },
|
||||||
maps: { table: 'maps', select: 'id, name', order: 'name' }
|
maps: { table: 'maps', order: 'name' }
|
||||||
};
|
};
|
||||||
|
|
||||||
function asString(value: QueryValue): string | undefined {
|
function asString(value: QueryValue): string | undefined {
|
||||||
@@ -112,10 +110,6 @@ function auditJoins(entityAlias: string, createdAlias = 'created_user', updatedA
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function configSelect(definition: ConfigDefinition): string {
|
|
||||||
return definition.hasSubcategory ? 'c.id, c.name, c.subcategory' : 'c.id, c.name';
|
|
||||||
}
|
|
||||||
|
|
||||||
function configOrder(definition: ConfigDefinition): string {
|
function configOrder(definition: ConfigDefinition): string {
|
||||||
return definition.order
|
return definition.order
|
||||||
.split(', ')
|
.split(', ')
|
||||||
@@ -215,7 +209,7 @@ const pokemonProjection = `
|
|||||||
${auditSelect('p', 'pokemon_created_user', 'pokemon_updated_user')},
|
${auditSelect('p', 'pokemon_created_user', 'pokemon_updated_user')},
|
||||||
json_build_object('id', e.id, 'name', e.name) AS environment,
|
json_build_object('id', e.id, 'name', e.name) AS environment,
|
||||||
COALESCE((
|
COALESCE((
|
||||||
SELECT json_agg(json_build_object('id', s.id, 'name', s.name, 'subcategory', s.subcategory) ORDER BY s.name, s.subcategory)
|
SELECT json_agg(json_build_object('id', s.id, 'name', s.name) ORDER BY s.name)
|
||||||
FROM pokemon_skills ps
|
FROM pokemon_skills ps
|
||||||
JOIN skills s ON s.id = ps.skill_id
|
JOIN skills s ON s.id = ps.skill_id
|
||||||
WHERE ps.pokemon_id = p.id
|
WHERE ps.pokemon_id = p.id
|
||||||
@@ -241,9 +235,7 @@ export async function getOptions() {
|
|||||||
acquisitionMethods,
|
acquisitionMethods,
|
||||||
maps
|
maps
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
query<{ id: number; name: string; subcategory: string | null }>(
|
optionSelect('skills'),
|
||||||
'SELECT id, name, subcategory FROM skills ORDER BY name, subcategory'
|
|
||||||
),
|
|
||||||
optionSelect('environments'),
|
optionSelect('environments'),
|
||||||
optionSelect('favorite_things'),
|
optionSelect('favorite_things'),
|
||||||
optionSelect('item_categories'),
|
optionSelect('item_categories'),
|
||||||
@@ -272,7 +264,7 @@ export async function listConfig(type: ConfigType) {
|
|||||||
const definition = configDefinitions[type];
|
const definition = configDefinitions[type];
|
||||||
return query(
|
return query(
|
||||||
`
|
`
|
||||||
SELECT ${configSelect(definition)}, ${auditSelect('c')}
|
SELECT c.id, c.name, ${auditSelect('c')}
|
||||||
FROM ${definition.table} c
|
FROM ${definition.table} c
|
||||||
${auditJoins('c')}
|
${auditJoins('c')}
|
||||||
ORDER BY ${configOrder(definition)}
|
ORDER BY ${configOrder(definition)}
|
||||||
@@ -284,7 +276,7 @@ async function getConfigById(type: ConfigType, id: number) {
|
|||||||
const definition = configDefinitions[type];
|
const definition = configDefinitions[type];
|
||||||
return queryOne(
|
return queryOne(
|
||||||
`
|
`
|
||||||
SELECT ${configSelect(definition)}, ${auditSelect('c')}
|
SELECT c.id, c.name, ${auditSelect('c')}
|
||||||
FROM ${definition.table} c
|
FROM ${definition.table} c
|
||||||
${auditJoins('c')}
|
${auditJoins('c')}
|
||||||
WHERE c.id = $1
|
WHERE c.id = $1
|
||||||
@@ -296,26 +288,16 @@ async function getConfigById(type: ConfigType, id: number) {
|
|||||||
export async function createConfig(type: ConfigType, payload: Record<string, unknown>, userId: number) {
|
export async function createConfig(type: ConfigType, payload: Record<string, unknown>, userId: number) {
|
||||||
const definition = configDefinitions[type];
|
const definition = configDefinitions[type];
|
||||||
const name = cleanName(payload.name);
|
const name = cleanName(payload.name);
|
||||||
const subcategory = typeof payload.subcategory === 'string' && payload.subcategory.trim() ? payload.subcategory.trim() : null;
|
|
||||||
|
|
||||||
const id = await withTransaction(async (client) => {
|
const id = await withTransaction(async (client) => {
|
||||||
const result = definition.hasSubcategory
|
const result = await client.query<{ id: number }>(
|
||||||
? await client.query<{ id: number }>(
|
`
|
||||||
`
|
INSERT INTO ${definition.table} (name, created_by_user_id, updated_by_user_id)
|
||||||
INSERT INTO ${definition.table} (name, subcategory, created_by_user_id, updated_by_user_id)
|
VALUES ($1, $2, $2)
|
||||||
VALUES ($1, $2, $3, $3)
|
RETURNING id
|
||||||
RETURNING id
|
`,
|
||||||
`,
|
[name, userId]
|
||||||
[name, subcategory, userId]
|
);
|
||||||
)
|
|
||||||
: await client.query<{ id: number }>(
|
|
||||||
`
|
|
||||||
INSERT INTO ${definition.table} (name, created_by_user_id, updated_by_user_id)
|
|
||||||
VALUES ($1, $2, $2)
|
|
||||||
RETURNING id
|
|
||||||
`,
|
|
||||||
[name, userId]
|
|
||||||
);
|
|
||||||
|
|
||||||
const createdId = result.rows[0].id;
|
const createdId = result.rows[0].id;
|
||||||
await recordEditLog(client, type, createdId, 'create', userId);
|
await recordEditLog(client, type, createdId, 'create', userId);
|
||||||
@@ -328,26 +310,16 @@ export async function createConfig(type: ConfigType, payload: Record<string, unk
|
|||||||
export async function updateConfig(type: ConfigType, id: number, payload: Record<string, unknown>, userId: number) {
|
export async function updateConfig(type: ConfigType, id: number, payload: Record<string, unknown>, userId: number) {
|
||||||
const definition = configDefinitions[type];
|
const definition = configDefinitions[type];
|
||||||
const name = cleanName(payload.name);
|
const name = cleanName(payload.name);
|
||||||
const subcategory = typeof payload.subcategory === 'string' && payload.subcategory.trim() ? payload.subcategory.trim() : null;
|
|
||||||
|
|
||||||
const updated = await withTransaction(async (client) => {
|
const updated = await withTransaction(async (client) => {
|
||||||
const result = definition.hasSubcategory
|
const result = await client.query(
|
||||||
? await client.query(
|
`
|
||||||
`
|
UPDATE ${definition.table}
|
||||||
UPDATE ${definition.table}
|
SET name = $1, updated_by_user_id = $2, updated_at = now()
|
||||||
SET name = $1, subcategory = $2, updated_by_user_id = $3, updated_at = now()
|
WHERE id = $3
|
||||||
WHERE id = $4
|
`,
|
||||||
`,
|
[name, userId, id]
|
||||||
[name, subcategory, userId, id]
|
);
|
||||||
)
|
|
||||||
: await client.query(
|
|
||||||
`
|
|
||||||
UPDATE ${definition.table}
|
|
||||||
SET name = $1, updated_by_user_id = $2, updated_at = now()
|
|
||||||
WHERE id = $3
|
|
||||||
`,
|
|
||||||
[name, userId, id]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result.rowCount === 0) {
|
if (result.rowCount === 0) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -2,15 +2,14 @@
|
|||||||
import type { NamedEntity } from '../services/api';
|
import type { NamedEntity } from '../services/api';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
items: Array<NamedEntity & { subcategory?: string | null; quantity?: number }>;
|
items: Array<NamedEntity & { quantity?: number }>;
|
||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="chips">
|
<div class="chips">
|
||||||
<span v-for="item in items" :key="`${item.id}-${item.name}`" class="chip">
|
<span v-for="item in items" :key="`${item.id}-${item.name}`" class="chip">
|
||||||
{{ item.name }}<span v-if="item.subcategory"> · {{ item.subcategory }}</span
|
{{ item.name }}<span v-if="item.quantity"> × {{ item.quantity }}</span>
|
||||||
><span v-if="item.quantity"> × {{ item.quantity }}</span>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ export type TagsSelectOption = {
|
|||||||
id: number | string;
|
id: number | string;
|
||||||
name: string;
|
name: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
subcategory?: string | null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type OptionRow = {
|
type OptionRow = {
|
||||||
@@ -56,7 +55,7 @@ const activeIndex = ref(-1);
|
|||||||
const optionRows = computed(() =>
|
const optionRows = computed(() =>
|
||||||
props.options.map((option, index) => ({
|
props.options.map((option, index) => ({
|
||||||
value: String(option.id),
|
value: String(option.id),
|
||||||
label: option.label ?? (option.subcategory ? `${option.name} · ${option.subcategory}` : option.name),
|
label: option.label ?? option.name,
|
||||||
id: `${props.id}-option-${index}`
|
id: `${props.id}-option-${index}`
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,10 +7,6 @@ export interface NamedEntity {
|
|||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Skill extends NamedEntity {
|
|
||||||
subcategory: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserSummary {
|
export interface UserSummary {
|
||||||
id: number;
|
id: number;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
@@ -27,7 +23,7 @@ export interface Pokemon extends EditInfo {
|
|||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
environment: NamedEntity;
|
environment: NamedEntity;
|
||||||
skills: Skill[];
|
skills: NamedEntity[];
|
||||||
favorite_things: NamedEntity[];
|
favorite_things: NamedEntity[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +85,7 @@ export interface RecipeDetail extends Recipe {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Options {
|
export interface Options {
|
||||||
skills: Skill[];
|
skills: NamedEntity[];
|
||||||
environments: NamedEntity[];
|
environments: NamedEntity[];
|
||||||
favoriteThings: NamedEntity[];
|
favoriteThings: NamedEntity[];
|
||||||
itemCategories: NamedEntity[];
|
itemCategories: NamedEntity[];
|
||||||
@@ -283,11 +279,11 @@ export const api = {
|
|||||||
me: () => getJson<{ user: AuthUser }>('/api/auth/me'),
|
me: () => getJson<{ user: AuthUser }>('/api/auth/me'),
|
||||||
logout: () => postEmpty('/api/auth/logout'),
|
logout: () => postEmpty('/api/auth/logout'),
|
||||||
options: () => getJson<Options>('/api/options'),
|
options: () => getJson<Options>('/api/options'),
|
||||||
config: (type: ConfigType) => getJson<Array<Skill | NamedEntity>>(`/api/admin/config/${type}`),
|
config: (type: ConfigType) => getJson<NamedEntity[]>(`/api/admin/config/${type}`),
|
||||||
createConfig: (type: ConfigType, payload: { name: string; subcategory?: string | null }) =>
|
createConfig: (type: ConfigType, payload: { name: string }) =>
|
||||||
sendJson<Skill | NamedEntity>(`/api/admin/config/${type}`, 'POST', payload),
|
sendJson<NamedEntity>(`/api/admin/config/${type}`, 'POST', payload),
|
||||||
updateConfig: (type: ConfigType, id: number, payload: { name: string; subcategory?: string | null }) =>
|
updateConfig: (type: ConfigType, id: number, payload: { name: string }) =>
|
||||||
sendJson<Skill | NamedEntity>(`/api/admin/config/${type}/${id}`, 'PUT', payload),
|
sendJson<NamedEntity>(`/api/admin/config/${type}/${id}`, 'PUT', payload),
|
||||||
deleteConfig: (type: ConfigType, id: number) => deleteJson(`/api/admin/config/${type}/${id}`),
|
deleteConfig: (type: ConfigType, id: number) => deleteJson(`/api/admin/config/${type}/${id}`),
|
||||||
pokemon: (params: Record<string, string | number | undefined>) =>
|
pokemon: (params: Record<string, string | number | undefined>) =>
|
||||||
getJson<Pokemon[]>(`/api/pokemon${buildQuery(params)}`),
|
getJson<Pokemon[]>(`/api/pokemon${buildQuery(params)}`),
|
||||||
|
|||||||
@@ -12,12 +12,11 @@ import {
|
|||||||
type Item,
|
type Item,
|
||||||
type NamedEntity,
|
type NamedEntity,
|
||||||
type Pokemon,
|
type Pokemon,
|
||||||
type Recipe,
|
type Recipe
|
||||||
type Skill
|
|
||||||
} from '../services/api';
|
} from '../services/api';
|
||||||
|
|
||||||
type AdminTab = 'config' | 'pokemon' | 'items' | 'recipes' | 'habitats';
|
type AdminTab = 'config' | 'pokemon' | 'items' | 'recipes' | 'habitats';
|
||||||
type EditableConfig = (NamedEntity | Skill) & { subcategory?: string | null };
|
type EditableConfig = NamedEntity;
|
||||||
|
|
||||||
const tabs: Array<{ key: AdminTab; label: string }> = [
|
const tabs: Array<{ key: AdminTab; label: string }> = [
|
||||||
{ key: 'config', label: '系统配置' },
|
{ key: 'config', label: '系统配置' },
|
||||||
@@ -27,8 +26,8 @@ const tabs: Array<{ key: AdminTab; label: string }> = [
|
|||||||
{ key: 'habitats', label: '栖息地' }
|
{ key: 'habitats', label: '栖息地' }
|
||||||
];
|
];
|
||||||
|
|
||||||
const configTypes: Array<{ key: ConfigType; label: string; hasSubcategory?: boolean }> = [
|
const configTypes: Array<{ key: ConfigType; label: string }> = [
|
||||||
{ key: 'skills', label: '特长', hasSubcategory: true },
|
{ key: 'skills', label: '特长' },
|
||||||
{ key: 'environments', label: '喜欢的环境' },
|
{ key: 'environments', label: '喜欢的环境' },
|
||||||
{ key: 'favorite-things', label: '喜欢的东西 / 标签' },
|
{ key: 'favorite-things', label: '喜欢的东西 / 标签' },
|
||||||
{ key: 'item-categories', label: '物品分类' },
|
{ key: 'item-categories', label: '物品分类' },
|
||||||
@@ -48,7 +47,7 @@ const currentUser = ref<AuthUser | null>(null);
|
|||||||
const busy = ref(false);
|
const busy = ref(false);
|
||||||
const contentLoading = ref(false);
|
const contentLoading = ref(false);
|
||||||
const message = ref('');
|
const message = ref('');
|
||||||
const configForm = ref({ id: 0, name: '', subcategory: '' });
|
const configForm = ref({ id: 0, name: '' });
|
||||||
|
|
||||||
const selectedConfig = computed(() => configTypes.find((item) => item.key === activeConfigType.value) ?? configTypes[0]);
|
const selectedConfig = computed(() => configTypes.find((item) => item.key === activeConfigType.value) ?? configTypes[0]);
|
||||||
const configTabs = computed<TabOption[]>(() => configTypes.map((item) => ({ value: item.key, label: item.label })));
|
const configTabs = computed<TabOption[]>(() => configTypes.map((item) => ({ value: item.key, label: item.label })));
|
||||||
@@ -87,18 +86,17 @@ async function loadConfig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resetConfigForm() {
|
function resetConfigForm() {
|
||||||
configForm.value = { id: 0, name: '', subcategory: '' };
|
configForm.value = { id: 0, name: '' };
|
||||||
}
|
}
|
||||||
|
|
||||||
function editConfig(item: EditableConfig) {
|
function editConfig(item: EditableConfig) {
|
||||||
configForm.value = { id: item.id, name: item.name, subcategory: item.subcategory ?? '' };
|
configForm.value = { id: item.id, name: item.name };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveConfig() {
|
async function saveConfig() {
|
||||||
await run(async () => {
|
await run(async () => {
|
||||||
const payload = {
|
const payload = {
|
||||||
name: configForm.value.name,
|
name: configForm.value.name
|
||||||
subcategory: selectedConfig.value.hasSubcategory ? configForm.value.subcategory || null : null
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (configForm.value.id) {
|
if (configForm.value.id) {
|
||||||
@@ -247,10 +245,6 @@ onMounted(() => {
|
|||||||
<label for="config-name">名称</label>
|
<label for="config-name">名称</label>
|
||||||
<input id="config-name" v-model="configForm.name" required />
|
<input id="config-name" v-model="configForm.name" required />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedConfig.hasSubcategory" class="field">
|
|
||||||
<label for="config-subcategory">二级分类</label>
|
|
||||||
<input id="config-subcategory" v-model="configForm.subcategory" />
|
|
||||||
</div>
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button type="submit" class="link-button" :disabled="busy">{{ busy ? '保存中' : '保存' }}</button>
|
<button type="submit" class="link-button" :disabled="busy">{{ busy ? '保存中' : '保存' }}</button>
|
||||||
<button type="button" class="plain-button" :disabled="busy" @click="resetConfigForm">新建</button>
|
<button type="button" class="plain-button" :disabled="busy" @click="resetConfigForm">新建</button>
|
||||||
@@ -260,7 +254,7 @@ onMounted(() => {
|
|||||||
<h3 class="section-subtitle">{{ selectedConfig.label }}</h3>
|
<h3 class="section-subtitle">{{ selectedConfig.label }}</h3>
|
||||||
<ul v-if="configRows.length" class="row-list">
|
<ul v-if="configRows.length" class="row-list">
|
||||||
<li v-for="item in configRows" :key="item.id">
|
<li v-for="item in configRows" :key="item.id">
|
||||||
<span>{{ item.name }}<span v-if="item.subcategory"> · {{ item.subcategory }}</span></span>
|
<span>{{ item.name }}</span>
|
||||||
<span class="row-actions">
|
<span class="row-actions">
|
||||||
<button type="button" @click="editConfig(item)">编辑</button>
|
<button type="button" @click="editConfig(item)">编辑</button>
|
||||||
<button type="button" @click="removeConfig(item.id)">删除</button>
|
<button type="button" @click="removeConfig(item.id)">删除</button>
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ async function createMultiOption(selectKey: string, type: ConfigType, name: stri
|
|||||||
creatingSelect.value = selectKey;
|
creatingSelect.value = selectKey;
|
||||||
message.value = '';
|
message.value = '';
|
||||||
try {
|
try {
|
||||||
const created = await api.createConfig(type, { name: cleanName, subcategory: null });
|
const created = await api.createConfig(type, { name: cleanName });
|
||||||
await loadOptions();
|
await loadOptions();
|
||||||
const value = String(created.id);
|
const value = String(created.id);
|
||||||
if (!values.includes(value)) {
|
if (!values.includes(value)) {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ async function createSingleOption(selectKey: string, type: ConfigType, name: str
|
|||||||
creatingSelect.value = selectKey;
|
creatingSelect.value = selectKey;
|
||||||
message.value = '';
|
message.value = '';
|
||||||
try {
|
try {
|
||||||
const created = await api.createConfig(type, { name: cleanName, subcategory: null });
|
const created = await api.createConfig(type, { name: cleanName });
|
||||||
await loadOptions();
|
await loadOptions();
|
||||||
assign(String(created.id));
|
assign(String(created.id));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -92,7 +92,7 @@ async function createMultiOption(selectKey: string, type: ConfigType, name: stri
|
|||||||
creatingSelect.value = selectKey;
|
creatingSelect.value = selectKey;
|
||||||
message.value = '';
|
message.value = '';
|
||||||
try {
|
try {
|
||||||
const created = await api.createConfig(type, { name: cleanName, subcategory: null });
|
const created = await api.createConfig(type, { name: cleanName });
|
||||||
await loadOptions();
|
await loadOptions();
|
||||||
const value = String(created.id);
|
const value = String(created.id);
|
||||||
if (!values.includes(value)) {
|
if (!values.includes(value)) {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ async function createSingleOption(selectKey: string, type: ConfigType, name: str
|
|||||||
creatingSelect.value = selectKey;
|
creatingSelect.value = selectKey;
|
||||||
message.value = '';
|
message.value = '';
|
||||||
try {
|
try {
|
||||||
const created = await api.createConfig(type, { name: cleanName, subcategory: null });
|
const created = await api.createConfig(type, { name: cleanName });
|
||||||
await loadOptions();
|
await loadOptions();
|
||||||
assign(String(created.id));
|
assign(String(created.id));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -86,7 +86,7 @@ async function createMultiOption(selectKey: string, type: ConfigType, name: stri
|
|||||||
creatingSelect.value = selectKey;
|
creatingSelect.value = selectKey;
|
||||||
message.value = '';
|
message.value = '';
|
||||||
try {
|
try {
|
||||||
const created = await api.createConfig(type, { name: cleanName, subcategory: null });
|
const created = await api.createConfig(type, { name: cleanName });
|
||||||
await loadOptions();
|
await loadOptions();
|
||||||
const value = String(created.id);
|
const value = String(created.id);
|
||||||
if (!values.includes(value)) {
|
if (!values.includes(value)) {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ async function createMultiOption(selectKey: string, type: ConfigType, name: stri
|
|||||||
creatingSelect.value = selectKey;
|
creatingSelect.value = selectKey;
|
||||||
message.value = '';
|
message.value = '';
|
||||||
try {
|
try {
|
||||||
const created = await api.createConfig(type, { name: cleanName, subcategory: null });
|
const created = await api.createConfig(type, { name: cleanName });
|
||||||
await loadOptions();
|
await loadOptions();
|
||||||
const value = String(created.id);
|
const value = String(created.id);
|
||||||
if (!values.includes(value)) {
|
if (!values.includes(value)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user