refactor: remove display ID from items and ancient artifacts
Drop display_id column from items and ancient_artifacts tables Remove display ID inputs, labels, and sorting logic across the stack BREAKING CHANGE: behavior is not backward compatible.
This commit is contained in:
16
DESIGN.md
16
DESIGN.md
@@ -593,7 +593,6 @@ Pokemon 详情页展示:
|
||||
|
||||
物品可配置:
|
||||
|
||||
- Display ID:用于物品和 Event Items 各自列表内展示与排序;`display_id` 与 `is_event_item` 组合唯一
|
||||
- 名称
|
||||
- 介绍
|
||||
- 是否为 Event Item:`is_event_item`
|
||||
@@ -638,8 +637,8 @@ Items 与 Event Items 使用相同数据模型:
|
||||
- 按分类展示为标签页
|
||||
- 按用途筛选
|
||||
- 按标签筛选
|
||||
- 按 Display ID 和自定义排序展示
|
||||
- 物品列表卡片使用与 Pokemon 列表一致的居中图鉴式布局,只展示物品图标、`#Display ID 名称` 和分类;不展示标签、入手方式或编辑元信息。
|
||||
- 按自定义排序展示
|
||||
- 物品列表卡片使用与 Pokemon 列表一致的居中图鉴式布局,只展示物品图标、名称和分类;不展示标签、入手方式或编辑元信息。
|
||||
- 有用途的物品在卡片左上角以斜 Ribbon 展示用途名称。
|
||||
- 已配置图标时,物品卡片展示图标缩略图;未配置图标时保留默认物品标记。
|
||||
|
||||
@@ -648,7 +647,6 @@ Items 与 Event Items 使用相同数据模型:
|
||||
- 基本信息
|
||||
- 当前图标图片;未配置图标时展示默认物品标记占位符
|
||||
- 顶部按图标 / 占位符与核心信息概览并排展示,移动端改为单列;顶部概览卡片不显示 `Image` / `Details` 通用区块标题,也不展示图片历史缩略图
|
||||
- Display ID
|
||||
- 介绍
|
||||
- 分类
|
||||
- 用途
|
||||
@@ -667,7 +665,6 @@ Items 与 Event Items 使用相同数据模型:
|
||||
|
||||
Ancient Artifacts 是独立 Wiki 内容类型,可配置:
|
||||
|
||||
- Display ID:用于展示与排序
|
||||
- 名称
|
||||
- 介绍
|
||||
- 图片:使用 Ancient Artifacts 上传目录,支持图片历史
|
||||
@@ -684,12 +681,11 @@ Ancient Artifacts 列表功能:
|
||||
- 搜索
|
||||
- 按分类展示为标签页
|
||||
- 按标签筛选
|
||||
- 按 Display ID 和自定义排序展示
|
||||
- 列表卡片使用与 Pokemon 列表一致的居中图鉴式布局,展示图片 / 默认 Ancient Artifact 标记、`#Display ID 名称` 和分类;不展示编辑元信息。
|
||||
- 按自定义排序展示
|
||||
- 列表卡片使用与 Pokemon 列表一致的居中图鉴式布局,展示图片 / 默认 Ancient Artifact 标记、名称和分类;不展示编辑元信息。
|
||||
|
||||
Ancient Artifacts 详情页展示:
|
||||
|
||||
- Display ID
|
||||
- 名称
|
||||
- 图片;未配置图片时展示默认 Ancient Artifact 标记
|
||||
- 介绍
|
||||
@@ -719,8 +715,8 @@ Ancient Artifacts 详情页展示:
|
||||
|
||||
- 独立于物品列表展示
|
||||
- 按结果物品分类展示
|
||||
- 按结果物品 Display ID 和自定义排序展示
|
||||
- 材料单列表卡片使用与 Pokemon 列表一致的居中图鉴式布局,按结果物品展示图标、`#Display ID 名称` 和分类;不展示编辑元信息。
|
||||
- 按自定义排序展示
|
||||
- 材料单列表卡片使用与 Pokemon 列表一致的居中图鉴式布局,按结果物品展示图标、名称和分类;不展示编辑元信息。
|
||||
- 有用途的结果物品在卡片左上角以斜 Ribbon 展示用途名称。
|
||||
- Create Recipe 按钮展示在结果物品名称下方;已有材料单的卡片保留同等按钮空间但不显示按钮;标记为无材料单的物品展示禁用按钮;可创建材料单的物品展示可点击按钮并进入创建流程。
|
||||
|
||||
|
||||
@@ -974,7 +974,6 @@ CREATE TABLE IF NOT EXISTS acquisition_methods (
|
||||
|
||||
CREATE TABLE IF NOT EXISTS items (
|
||||
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
display_id integer NOT NULL CHECK (display_id > 0),
|
||||
name text NOT NULL UNIQUE,
|
||||
details text NOT NULL DEFAULT '',
|
||||
category_key text NOT NULL DEFAULT 'other',
|
||||
@@ -1011,7 +1010,6 @@ CREATE TABLE IF NOT EXISTS items (
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ancient_artifacts (
|
||||
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
display_id integer NOT NULL UNIQUE CHECK (display_id > 0),
|
||||
name text NOT NULL UNIQUE,
|
||||
details text NOT NULL DEFAULT '',
|
||||
category_key text NOT NULL CHECK (category_key IN ('lost-relics-l', 'lost-relics-s', 'fossils')),
|
||||
@@ -1221,7 +1219,6 @@ ALTER TABLE life_tags
|
||||
ADD COLUMN IF NOT EXISTS is_default boolean NOT NULL DEFAULT false;
|
||||
|
||||
ALTER TABLE items
|
||||
ADD COLUMN IF NOT EXISTS display_id integer,
|
||||
ADD COLUMN IF NOT EXISTS details text NOT NULL DEFAULT '',
|
||||
ADD COLUMN IF NOT EXISTS category_key text,
|
||||
ADD COLUMN IF NOT EXISTS usage_key text;
|
||||
@@ -1242,10 +1239,6 @@ BEGIN
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
UPDATE items
|
||||
SET display_id = id
|
||||
WHERE display_id IS NULL;
|
||||
|
||||
UPDATE items i
|
||||
SET category_key = CASE lower(trim(c.name))
|
||||
WHEN 'furniture' THEN 'furniture'
|
||||
@@ -1303,7 +1296,6 @@ WHERE usage_key IS NOT NULL
|
||||
AND usage_key NOT IN ('decoration', 'relaxation', 'toy', 'road');
|
||||
|
||||
ALTER TABLE items
|
||||
ALTER COLUMN display_id SET NOT NULL,
|
||||
ALTER COLUMN category_key SET NOT NULL,
|
||||
ALTER COLUMN category_key SET DEFAULT 'other';
|
||||
|
||||
@@ -1313,7 +1305,6 @@ ALTER TABLE items
|
||||
DROP CONSTRAINT IF EXISTS items_usage_key_check;
|
||||
|
||||
ALTER TABLE items
|
||||
ADD CONSTRAINT items_display_id_positive CHECK (display_id > 0),
|
||||
ADD CONSTRAINT items_category_key_check CHECK (category_key IN (
|
||||
'furniture',
|
||||
'misc',
|
||||
@@ -1330,6 +1321,20 @@ ALTER TABLE items
|
||||
)),
|
||||
ADD CONSTRAINT items_usage_key_check CHECK (usage_key IS NULL OR usage_key IN ('decoration', 'relaxation', 'toy', 'road'));
|
||||
|
||||
DROP INDEX IF EXISTS items_display_event_item_key;
|
||||
DROP INDEX IF EXISTS items_display_order_idx;
|
||||
DROP INDEX IF EXISTS ancient_artifacts_display_order_idx;
|
||||
|
||||
ALTER TABLE ancient_artifacts
|
||||
DROP CONSTRAINT IF EXISTS ancient_artifacts_display_id_key,
|
||||
DROP CONSTRAINT IF EXISTS ancient_artifacts_display_id_check;
|
||||
|
||||
ALTER TABLE items
|
||||
DROP COLUMN IF EXISTS display_id;
|
||||
|
||||
ALTER TABLE ancient_artifacts
|
||||
DROP COLUMN IF EXISTS display_id;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS environments_sort_order_idx ON environments(sort_order, id);
|
||||
CREATE INDEX IF NOT EXISTS skills_sort_order_idx ON skills(sort_order, id);
|
||||
CREATE INDEX IF NOT EXISTS favorite_things_sort_order_idx ON favorite_things(sort_order, id);
|
||||
@@ -1342,10 +1347,7 @@ CREATE INDEX IF NOT EXISTS item_categories_sort_order_idx ON item_categories(sor
|
||||
CREATE INDEX IF NOT EXISTS item_usages_sort_order_idx ON item_usages(sort_order, id);
|
||||
CREATE INDEX IF NOT EXISTS acquisition_methods_sort_order_idx ON acquisition_methods(sort_order, id);
|
||||
CREATE INDEX IF NOT EXISTS items_sort_order_idx ON items(sort_order, id);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS items_display_event_item_key ON items(display_id, is_event_item);
|
||||
CREATE INDEX IF NOT EXISTS items_display_order_idx ON items(is_event_item, display_id, sort_order, id);
|
||||
CREATE INDEX IF NOT EXISTS ancient_artifacts_sort_order_idx ON ancient_artifacts(sort_order, id);
|
||||
CREATE INDEX IF NOT EXISTS ancient_artifacts_display_order_idx ON ancient_artifacts(display_id, sort_order, id);
|
||||
CREATE INDEX IF NOT EXISTS recipes_sort_order_idx ON recipes(sort_order, id);
|
||||
CREATE INDEX IF NOT EXISTS dish_categories_sort_order_idx ON dish_categories(sort_order, id);
|
||||
CREATE INDEX IF NOT EXISTS dish_flavors_sort_order_idx ON dish_flavors(sort_order, id);
|
||||
|
||||
@@ -201,7 +201,6 @@ type PokemonCsvData = {
|
||||
};
|
||||
|
||||
type ItemPayload = {
|
||||
displayId: number;
|
||||
name: string;
|
||||
details: string;
|
||||
translations: TranslationInput;
|
||||
@@ -220,7 +219,6 @@ type ItemPayload = {
|
||||
};
|
||||
|
||||
type AncientArtifactPayload = {
|
||||
displayId: number;
|
||||
name: string;
|
||||
details: string;
|
||||
translations: TranslationInput;
|
||||
@@ -541,7 +539,6 @@ type PokemonChangeSource = {
|
||||
favorite_things: Array<{ name: string }>;
|
||||
} & TranslationChangeSource;
|
||||
type ItemChangeSource = {
|
||||
displayId: number;
|
||||
name: string;
|
||||
details: string;
|
||||
isEventItem: boolean;
|
||||
@@ -554,7 +551,6 @@ type ItemChangeSource = {
|
||||
tags: Array<{ name: string }>;
|
||||
} & TranslationChangeSource;
|
||||
type AncientArtifactChangeSource = {
|
||||
displayId: number;
|
||||
name: string;
|
||||
details: string;
|
||||
image: EntityImageValue | null;
|
||||
@@ -2251,7 +2247,6 @@ async function itemEditChanges(
|
||||
const tagNames = await entityNameMap(client, 'favorite_things', after.tagIds);
|
||||
|
||||
pushChange(changes, 'Name', before.name, after.name);
|
||||
pushChange(changes, 'Display ID', String(before.displayId), String(after.displayId));
|
||||
pushChange(changes, 'Description', before.details, after.details);
|
||||
pushTranslationChanges(changes, before.translations, after.translations, ['name', 'details']);
|
||||
pushChange(changes, 'Event item', boolValue(before.isEventItem), boolValue(after.isEventItem));
|
||||
@@ -2277,7 +2272,6 @@ async function ancientArtifactEditChanges(
|
||||
const tagNames = await entityNameMap(client, 'favorite_things', after.tagIds);
|
||||
|
||||
pushChange(changes, 'Name', before.name, after.name);
|
||||
pushChange(changes, 'Display ID', String(before.displayId), String(after.displayId));
|
||||
pushChange(changes, 'Description', before.details, after.details);
|
||||
pushTranslationChanges(changes, before.translations, after.translations, ['name', 'details']);
|
||||
pushChange(changes, 'Image', imagePathLabel(before.image?.path), imagePathLabel(after.imagePath));
|
||||
@@ -2574,7 +2568,7 @@ export async function globalSearch(paramsQuery: QueryParams = {}, locale = defau
|
||||
${uploadedImageJson('i.image_path')} AS image
|
||||
FROM items i
|
||||
WHERE ${itemName} ILIKE $1
|
||||
ORDER BY i.display_id, ${orderByEntity('i')}
|
||||
ORDER BY ${orderByEntity('i')}
|
||||
LIMIT $2
|
||||
`,
|
||||
[pattern, limit]
|
||||
@@ -2591,7 +2585,7 @@ export async function globalSearch(paramsQuery: QueryParams = {}, locale = defau
|
||||
${uploadedImageJson('a.image_path')} AS image
|
||||
FROM ancient_artifacts a
|
||||
WHERE ${artifactName} ILIKE $1
|
||||
ORDER BY a.display_id, ${orderByEntity('a')}
|
||||
ORDER BY ${orderByEntity('a')}
|
||||
LIMIT $2
|
||||
`,
|
||||
[pattern, limit]
|
||||
@@ -6223,7 +6217,6 @@ function itemProjection(locale: string): string {
|
||||
return `
|
||||
SELECT
|
||||
i.id,
|
||||
i.display_id AS "displayId",
|
||||
${itemName} AS name,
|
||||
i.name AS "baseName",
|
||||
${itemDetails} AS details,
|
||||
@@ -6324,8 +6317,8 @@ export async function listItems(paramsQuery: QueryParams, locale = defaultLocale
|
||||
|
||||
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
||||
const orderClause = recipeOrder
|
||||
? `ORDER BY CASE WHEN item_recipe.id IS NULL THEN 1 ELSE 0 END, item_recipe.sort_order, item_recipe.id, i.display_id, ${orderByEntity('i')}`
|
||||
: `ORDER BY i.display_id, ${orderByEntity('i')}`;
|
||||
? `ORDER BY CASE WHEN item_recipe.id IS NULL THEN 1 ELSE 0 END, item_recipe.sort_order, item_recipe.id, ${orderByEntity('i')}`
|
||||
: `ORDER BY ${orderByEntity('i')}`;
|
||||
return query(`${itemProjection(locale)} ${whereClause} ${orderClause}`, params);
|
||||
}
|
||||
|
||||
@@ -6382,7 +6375,6 @@ export async function getItem(id: number, locale = defaultLocale) {
|
||||
), '[]'::json) AS materials,
|
||||
json_build_object(
|
||||
'id', result_item.id,
|
||||
'displayId', result_item.display_id,
|
||||
'name', ${resultItemName},
|
||||
'image', ${uploadedImageJson('result_item.image_path')},
|
||||
'category', ${systemListJsonSql('result_item.category_key', itemCategoryOptions, locale)},
|
||||
@@ -6489,7 +6481,6 @@ function cleanItemPayload(payload: Record<string, unknown>): ItemPayload {
|
||||
const usage = usageId === null ? null : systemListOptionById(itemUsageOptions, usageId, 'server.validation.usageRequired');
|
||||
|
||||
return {
|
||||
displayId: requirePositiveInteger(payload.displayId, 'server.validation.itemDisplayIdRequired'),
|
||||
name: cleanName(payload.name, 'server.validation.itemNameRequired'),
|
||||
details: cleanOptionalText(payload.details),
|
||||
translations: cleanTranslations(payload.translations, ['name', 'details']),
|
||||
@@ -6546,7 +6537,6 @@ export async function createItem(payload: Record<string, unknown>, userId: numbe
|
||||
const result = await client.query<{ id: number }>(
|
||||
`
|
||||
INSERT INTO items (
|
||||
display_id,
|
||||
name,
|
||||
details,
|
||||
category_key,
|
||||
@@ -6561,11 +6551,10 @@ export async function createItem(payload: Record<string, unknown>, userId: numbe
|
||||
created_by_user_id,
|
||||
updated_by_user_id
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $13)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $12)
|
||||
RETURNING id
|
||||
`,
|
||||
[
|
||||
cleanPayload.displayId,
|
||||
cleanPayload.name,
|
||||
cleanPayload.details,
|
||||
cleanPayload.categoryKey,
|
||||
@@ -6599,23 +6588,21 @@ export async function updateItem(id: number, payload: Record<string, unknown>, u
|
||||
const result = await client.query(
|
||||
`
|
||||
UPDATE items
|
||||
SET display_id = $1,
|
||||
name = $2,
|
||||
details = $3,
|
||||
category_key = $4,
|
||||
usage_key = $5,
|
||||
dyeable = $6,
|
||||
dual_dyeable = $7,
|
||||
pattern_editable = $8,
|
||||
no_recipe = $9,
|
||||
is_event_item = $10,
|
||||
image_path = $11,
|
||||
updated_by_user_id = $12,
|
||||
SET name = $1,
|
||||
details = $2,
|
||||
category_key = $3,
|
||||
usage_key = $4,
|
||||
dyeable = $5,
|
||||
dual_dyeable = $6,
|
||||
pattern_editable = $7,
|
||||
no_recipe = $8,
|
||||
is_event_item = $9,
|
||||
image_path = $10,
|
||||
updated_by_user_id = $11,
|
||||
updated_at = now()
|
||||
WHERE id = $13
|
||||
WHERE id = $12
|
||||
`,
|
||||
[
|
||||
cleanPayload.displayId,
|
||||
cleanPayload.name,
|
||||
cleanPayload.details,
|
||||
cleanPayload.categoryKey,
|
||||
@@ -6665,7 +6652,6 @@ function ancientArtifactProjection(locale: string): string {
|
||||
return `
|
||||
SELECT
|
||||
a.id,
|
||||
a.display_id AS "displayId",
|
||||
${artifactName} AS name,
|
||||
a.name AS "baseName",
|
||||
${artifactDetails} AS details,
|
||||
@@ -6719,7 +6705,7 @@ export async function listAncientArtifacts(paramsQuery: QueryParams = {}, locale
|
||||
}
|
||||
|
||||
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
||||
return query(`${ancientArtifactProjection(locale)} ${whereClause} ORDER BY a.display_id, ${orderByEntity('a')}`, params);
|
||||
return query(`${ancientArtifactProjection(locale)} ${whereClause} ORDER BY ${orderByEntity('a')}`, params);
|
||||
}
|
||||
|
||||
export async function getAncientArtifact(id: number, locale = defaultLocale) {
|
||||
@@ -6738,7 +6724,6 @@ function cleanAncientArtifactPayload(payload: Record<string, unknown>): AncientA
|
||||
const category = systemListOptionById(ancientArtifactCategoryOptions, categoryId, 'server.validation.categoryRequired');
|
||||
|
||||
return {
|
||||
displayId: requirePositiveInteger(payload.displayId, 'server.validation.artifactDisplayIdRequired'),
|
||||
name: cleanName(payload.name, 'server.validation.artifactNameRequired'),
|
||||
details: cleanOptionalText(payload.details),
|
||||
translations: cleanTranslations(payload.translations, ['name', 'details']),
|
||||
@@ -6768,7 +6753,6 @@ export async function createAncientArtifact(payload: Record<string, unknown>, us
|
||||
const result = await client.query<{ id: number }>(
|
||||
`
|
||||
INSERT INTO ancient_artifacts (
|
||||
display_id,
|
||||
name,
|
||||
details,
|
||||
category_key,
|
||||
@@ -6777,11 +6761,10 @@ export async function createAncientArtifact(payload: Record<string, unknown>, us
|
||||
created_by_user_id,
|
||||
updated_by_user_id
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $7)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $6)
|
||||
RETURNING id
|
||||
`,
|
||||
[
|
||||
cleanPayload.displayId,
|
||||
cleanPayload.name,
|
||||
cleanPayload.details,
|
||||
cleanPayload.categoryKey,
|
||||
@@ -6809,16 +6792,15 @@ export async function updateAncientArtifact(id: number, payload: Record<string,
|
||||
const result = await client.query(
|
||||
`
|
||||
UPDATE ancient_artifacts
|
||||
SET display_id = $1,
|
||||
name = $2,
|
||||
details = $3,
|
||||
category_key = $4,
|
||||
image_path = $5,
|
||||
updated_by_user_id = $6,
|
||||
SET name = $1,
|
||||
details = $2,
|
||||
category_key = $3,
|
||||
image_path = $4,
|
||||
updated_by_user_id = $5,
|
||||
updated_at = now()
|
||||
WHERE id = $7
|
||||
WHERE id = $6
|
||||
`,
|
||||
[cleanPayload.displayId, cleanPayload.name, cleanPayload.details, cleanPayload.categoryKey, cleanPayload.imagePath, userId, id]
|
||||
[cleanPayload.name, cleanPayload.details, cleanPayload.categoryKey, cleanPayload.imagePath, userId, id]
|
||||
);
|
||||
if (result.rowCount === 0) {
|
||||
return false;
|
||||
@@ -6917,7 +6899,6 @@ export async function getRecipe(id: number, locale = defaultLocale) {
|
||||
), '[]'::json) AS materials,
|
||||
json_build_object(
|
||||
'id', result_item.id,
|
||||
'displayId', result_item.display_id,
|
||||
'name', ${resultItemName},
|
||||
'image', ${uploadedImageJson('result_item.image_path')},
|
||||
'category', ${systemListJsonSql('result_item.category_key', itemCategoryOptions, locale)},
|
||||
@@ -7060,14 +7041,12 @@ function dishCategoryProjection(locale: string): string {
|
||||
${auditSelect('dc', 'category_created_user', 'category_updated_user')},
|
||||
json_build_object(
|
||||
'id', cookware_item.id,
|
||||
'displayId', cookware_item.display_id,
|
||||
'name', ${cookwareName},
|
||||
'image', ${uploadedImageJson('cookware_item.image_path')},
|
||||
'category', ${systemListJsonSql('cookware_item.category_key', itemCategoryOptions, locale)}
|
||||
) AS cookware,
|
||||
json_build_object(
|
||||
'id', main_material_item.id,
|
||||
'displayId', main_material_item.display_id,
|
||||
'name', ${mainMaterialName},
|
||||
'image', ${uploadedImageJson('main_material_item.image_path')},
|
||||
'category', ${systemListJsonSql('main_material_item.category_key', itemCategoryOptions, locale)}
|
||||
@@ -7093,7 +7072,6 @@ function dishCategoryProjection(locale: string): string {
|
||||
'category', json_build_object('id', dc.id, 'name', ${categoryName}),
|
||||
'item', json_build_object(
|
||||
'id', dish_item.id,
|
||||
'displayId', dish_item.display_id,
|
||||
'name', ${dishItemName},
|
||||
'image', ${uploadedImageJson('dish_item.image_path')},
|
||||
'category', ${systemListJsonSql('dish_item.category_key', itemCategoryOptions, locale)}
|
||||
@@ -7102,7 +7080,6 @@ function dishCategoryProjection(locale: string): string {
|
||||
SELECT json_agg(
|
||||
json_build_object(
|
||||
'id', secondary_material_item.id,
|
||||
'displayId', secondary_material_item.display_id,
|
||||
'name', ${secondaryMaterialName},
|
||||
'image', ${uploadedImageJson('secondary_material_item.image_path')},
|
||||
'category', ${systemListJsonSql('secondary_material_item.category_key', itemCategoryOptions, locale)}
|
||||
@@ -7153,7 +7130,6 @@ function dishProjection(locale: string): string {
|
||||
json_build_object('id', dc.id, 'name', ${categoryName}) AS category,
|
||||
json_build_object(
|
||||
'id', dish_item.id,
|
||||
'displayId', dish_item.display_id,
|
||||
'name', ${dishItemName},
|
||||
'image', ${uploadedImageJson('dish_item.image_path')},
|
||||
'category', ${systemListJsonSql('dish_item.category_key', itemCategoryOptions, locale)}
|
||||
@@ -7162,7 +7138,6 @@ function dishProjection(locale: string): string {
|
||||
SELECT json_agg(
|
||||
json_build_object(
|
||||
'id', secondary_material_item.id,
|
||||
'displayId', secondary_material_item.display_id,
|
||||
'name', ${secondaryMaterialName},
|
||||
'image', ${uploadedImageJson('secondary_material_item.image_path')},
|
||||
'category', ${systemListJsonSql('secondary_material_item.category_key', itemCategoryOptions, locale)}
|
||||
@@ -7568,7 +7543,6 @@ const dataToolColumns = {
|
||||
habitatPokemon: ['habitat_id', 'pokemon_id', 'map_id', 'time_of_day', 'weather', 'rarity'],
|
||||
items: [
|
||||
'id',
|
||||
'display_id',
|
||||
'name',
|
||||
'details',
|
||||
'category_key',
|
||||
@@ -7590,7 +7564,6 @@ const dataToolColumns = {
|
||||
artifactFavoriteThings: ['ancient_artifact_id', 'favorite_thing_id'],
|
||||
artifacts: [
|
||||
'id',
|
||||
'display_id',
|
||||
'name',
|
||||
'details',
|
||||
'category_key',
|
||||
@@ -7901,7 +7874,7 @@ async function exportScopeData(client: DbClient, scope: DataToolScope): Promise<
|
||||
|
||||
if (scope === 'items') {
|
||||
return {
|
||||
items: await tableRows(client, 'SELECT * FROM items ORDER BY display_id, sort_order, id'),
|
||||
items: await tableRows(client, 'SELECT * FROM items ORDER BY sort_order, id'),
|
||||
itemAcquisitionMethods: await tableRows(client, 'SELECT * FROM item_acquisition_methods ORDER BY item_id, acquisition_method_id'),
|
||||
itemFavoriteThings: await tableRows(client, 'SELECT * FROM item_favorite_things ORDER BY item_id, favorite_thing_id'),
|
||||
pokemonSkillItemDrops: await tableRows(client, 'SELECT * FROM pokemon_skill_item_drops ORDER BY pokemon_id, skill_id'),
|
||||
@@ -7912,7 +7885,7 @@ async function exportScopeData(client: DbClient, scope: DataToolScope): Promise<
|
||||
|
||||
if (scope === 'artifacts') {
|
||||
return {
|
||||
artifacts: await tableRows(client, 'SELECT * FROM ancient_artifacts ORDER BY display_id, sort_order, id'),
|
||||
artifacts: await tableRows(client, 'SELECT * FROM ancient_artifacts ORDER BY sort_order, id'),
|
||||
artifactFavoriteThings: await tableRows(
|
||||
client,
|
||||
'SELECT * FROM ancient_artifact_favorite_things ORDER BY ancient_artifact_id, favorite_thing_id'
|
||||
|
||||
@@ -16,7 +16,6 @@ const changeLabelKeys: Record<string, string> = {
|
||||
标题: 'pages.checklist.task',
|
||||
'Pokemon ID': 'pages.pokemon.id',
|
||||
'Pokopia ID': 'pages.pokemon.id',
|
||||
'Display ID': 'pages.items.displayId',
|
||||
'Event item': 'common.eventItem',
|
||||
'Event Pokemon': 'pages.pokemon.eventItem',
|
||||
'Event Habitat': 'pages.habitats.eventItem',
|
||||
@@ -118,12 +117,17 @@ function changeValue(value: string): string {
|
||||
return values[value] ?? value;
|
||||
}
|
||||
|
||||
function visibleChanges(entry: EditHistoryEntry) {
|
||||
return entry.changes.filter((change) => change.label !== 'Display ID');
|
||||
}
|
||||
|
||||
function historySummary(entry: EditHistoryEntry): string {
|
||||
if (!entry.changes.length) {
|
||||
const changes = visibleChanges(entry);
|
||||
if (!changes.length) {
|
||||
return actionLabel(entry.action);
|
||||
}
|
||||
|
||||
return entry.changes.map((change) => changeLabel(change.label)).join(locale.value === 'zh-CN' ? '、' : ', ');
|
||||
return changes.map((change) => changeLabel(change.label)).join(locale.value === 'zh-CN' ? '、' : ', ');
|
||||
}
|
||||
|
||||
function formatDateTime(value: string): string {
|
||||
@@ -175,8 +179,8 @@ function formatDateTime(value: string): string {
|
||||
</summary>
|
||||
|
||||
<div class="edit-history-entry__content">
|
||||
<dl v-if="entry.changes.length" class="edit-change-list">
|
||||
<div v-for="change in entry.changes" :key="`${change.label}-${change.before}-${change.after}`">
|
||||
<dl v-if="visibleChanges(entry).length" class="edit-change-list">
|
||||
<div v-for="change in visibleChanges(entry)" :key="`${change.label}-${change.before}-${change.after}`">
|
||||
<dt>{{ changeLabel(change.label) }}</dt>
|
||||
<dd>
|
||||
<span class="edit-change-list__label">{{ t('history.before') }}</span>
|
||||
|
||||
@@ -246,7 +246,6 @@ export interface HabitatUsage {
|
||||
}
|
||||
|
||||
export interface RecipeResultItem extends NamedEntity {
|
||||
displayId: number;
|
||||
image?: EntityImage | null;
|
||||
category?: NamedEntity;
|
||||
usage?: NamedEntity | null;
|
||||
@@ -254,7 +253,6 @@ export interface RecipeResultItem extends NamedEntity {
|
||||
|
||||
export interface Item extends EditInfo {
|
||||
id: number;
|
||||
displayId: number;
|
||||
name: string;
|
||||
baseName?: string;
|
||||
details: string;
|
||||
@@ -276,7 +274,6 @@ export interface Item extends EditInfo {
|
||||
|
||||
export interface AncientArtifact extends EditInfo {
|
||||
id: number;
|
||||
displayId: number;
|
||||
name: string;
|
||||
baseName?: string;
|
||||
details: string;
|
||||
@@ -312,7 +309,6 @@ export interface Recipe extends EditInfo {
|
||||
}
|
||||
|
||||
export interface ItemLink extends NamedEntity {
|
||||
displayId: number;
|
||||
image?: EntityImage | null;
|
||||
category?: NamedEntity;
|
||||
}
|
||||
@@ -791,7 +787,6 @@ export interface PokemonImageOptionsResult {
|
||||
}
|
||||
|
||||
export interface ItemPayload {
|
||||
displayId: number;
|
||||
name: string;
|
||||
details: string;
|
||||
translations?: TranslationMap;
|
||||
@@ -808,7 +803,6 @@ export interface ItemPayload {
|
||||
}
|
||||
|
||||
export interface AncientArtifactPayload {
|
||||
displayId: number;
|
||||
name: string;
|
||||
details: string;
|
||||
translations?: TranslationMap;
|
||||
|
||||
@@ -448,15 +448,15 @@ const configLabel = (item: EditableConfig) => item.name;
|
||||
const pokemonKey = (item: Pokemon) => item.id;
|
||||
const pokemonLabel = (item: Pokemon) => `#${item.displayId} ${item.name}`;
|
||||
const itemKey = (item: Item) => item.id;
|
||||
const itemLabel = (item: Item) => `#${item.displayId} ${item.name}`;
|
||||
const itemLabel = (item: Item) => item.name;
|
||||
const ancientArtifactKey = (item: AncientArtifact) => item.id;
|
||||
const ancientArtifactLabel = (item: AncientArtifact) => `#${item.displayId} ${item.name}`;
|
||||
const ancientArtifactLabel = (item: AncientArtifact) => item.name;
|
||||
const recipeKey = (item: Recipe) => item.id;
|
||||
const recipeLabel = (item: Recipe) => item.name;
|
||||
const dishCategoryKey = (item: DishCategory) => item.id;
|
||||
const dishCategoryLabel = (item: DishCategory) => item.name;
|
||||
const dishKey = (item: Dish) => item.id;
|
||||
const dishLabel = (item: Dish) => `#${item.item.displayId} ${item.item.name}`;
|
||||
const dishLabel = (item: Dish) => item.item.name;
|
||||
const habitatKey = (item: Habitat) => item.id;
|
||||
const habitatLabel = (item: Habitat) => item.name;
|
||||
|
||||
@@ -2260,7 +2260,7 @@ onMounted(() => {
|
||||
@reorder="persistItemOrder"
|
||||
>
|
||||
<template #default="{ item }">
|
||||
<RouterLink :to="`/items/${item.id}`">#{{ item.displayId }} {{ item.name }}</RouterLink>
|
||||
<RouterLink :to="`/items/${item.id}`">{{ item.name }}</RouterLink>
|
||||
<span class="row-actions">
|
||||
<button v-if="can('items.delete')" type="button" :disabled="busy" @click="removeItem(item.id)">
|
||||
<Icon :icon="iconDelete" class="ui-icon" aria-hidden="true" />
|
||||
@@ -2288,7 +2288,7 @@ onMounted(() => {
|
||||
@reorder="persistAncientArtifactOrder"
|
||||
>
|
||||
<template #default="{ item }">
|
||||
<RouterLink :to="`/ancient-artifacts/${item.id}`">#{{ item.displayId }} {{ item.name }}</RouterLink>
|
||||
<RouterLink :to="`/ancient-artifacts/${item.id}`">{{ item.name }}</RouterLink>
|
||||
<span class="row-actions">
|
||||
<button v-if="can('ancient-artifacts.delete')" type="button" :disabled="busy" @click="removeAncientArtifact(item.id)">
|
||||
<Icon :icon="iconDelete" class="ui-icon" aria-hidden="true" />
|
||||
@@ -2389,7 +2389,7 @@ onMounted(() => {
|
||||
@reorder="persistDishOrder"
|
||||
>
|
||||
<template #default="{ item }">
|
||||
<RouterLink :to="`/items/${item.item.id}`">#{{ item.item.displayId }} {{ item.item.name }}</RouterLink>
|
||||
<RouterLink :to="`/items/${item.item.id}`">{{ item.item.name }}</RouterLink>
|
||||
<span class="meta-line">{{ item.category.name }} / {{ item.flavor.name }}</span>
|
||||
<span class="row-actions">
|
||||
<button v-if="can('dish.update')" type="button" :disabled="busy" @click="editDish(item)">
|
||||
@@ -2658,7 +2658,7 @@ onMounted(() => {
|
||||
<label for="dish-category-cookware">{{ t('pages.dish.cookware') }}</label>
|
||||
<select id="dish-category-cookware" v-model="dishCategoryForm.cookwareItemId" required>
|
||||
<option value="">{{ t('common.none') }}</option>
|
||||
<option v-for="item in dishItemRows" :key="`cookware-${item.id}`" :value="String(item.id)">#{{ item.displayId }} {{ item.name }}</option>
|
||||
<option v-for="item in dishItemRows" :key="`cookware-${item.id}`" :value="String(item.id)">{{ item.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
@@ -2669,7 +2669,7 @@ onMounted(() => {
|
||||
<label for="dish-category-main-material">{{ t('pages.dish.mainMaterial') }}</label>
|
||||
<select id="dish-category-main-material" v-model="dishCategoryForm.mainMaterialItemId" required>
|
||||
<option value="">{{ t('common.none') }}</option>
|
||||
<option v-for="item in dishItemRows" :key="`category-main-material-${item.id}`" :value="String(item.id)">#{{ item.displayId }} {{ item.name }}</option>
|
||||
<option v-for="item in dishItemRows" :key="`category-main-material-${item.id}`" :value="String(item.id)">{{ item.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2710,7 +2710,7 @@ onMounted(() => {
|
||||
<label for="dish-item">{{ t('pages.dish.dishItem') }}</label>
|
||||
<select id="dish-item" v-model="dishForm.itemId" required>
|
||||
<option value="">{{ t('common.none') }}</option>
|
||||
<option v-for="item in dishItemRows" :key="`dish-item-${item.id}`" :value="String(item.id)">#{{ item.displayId }} {{ item.name }}</option>
|
||||
<option v-for="item in dishItemRows" :key="`dish-item-${item.id}`" :value="String(item.id)">{{ item.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
@@ -2726,14 +2726,14 @@ onMounted(() => {
|
||||
<label for="dish-secondary-material-1">{{ t('pages.dish.secondaryMaterial') }}</label>
|
||||
<select id="dish-secondary-material-1" v-model="dishForm.secondaryMaterialItemIds[0]">
|
||||
<option value="">{{ t('common.none') }}</option>
|
||||
<option v-for="item in dishItemRows" :key="`dish-secondary-material-1-${item.id}`" :value="String(item.id)">#{{ item.displayId }} {{ item.name }}</option>
|
||||
<option v-for="item in dishItemRows" :key="`dish-secondary-material-1-${item.id}`" :value="String(item.id)">{{ item.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div v-if="dishAllowsSecondSecondaryMaterial" class="field">
|
||||
<label for="dish-secondary-material-2">{{ t('pages.dish.secondSecondaryMaterial') }}</label>
|
||||
<select id="dish-secondary-material-2" v-model="dishForm.secondaryMaterialItemIds[1]">
|
||||
<option value="">{{ t('common.none') }}</option>
|
||||
<option v-for="item in dishItemRows" :key="`dish-secondary-material-2-${item.id}`" :value="String(item.id)">#{{ item.displayId }} {{ item.name }}</option>
|
||||
<option v-for="item in dishItemRows" :key="`dish-secondary-material-2-${item.id}`" :value="String(item.id)">{{ item.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
|
||||
@@ -96,7 +96,7 @@ watch(
|
||||
</section>
|
||||
</section>
|
||||
<section v-else class="page-stack">
|
||||
<PageHeader :title="`#${artifact.displayId} ${artifact.name}`" :subtitle="artifact.category.name">
|
||||
<PageHeader :title="artifact.name" :subtitle="artifact.category.name">
|
||||
<template #kicker>{{ t('pages.ancientArtifacts.detailKicker') }}</template>
|
||||
<template #actions>
|
||||
<RouterLink v-if="canUpdateArtifact" class="ui-button ui-button--primary ui-button--small" :to="`/ancient-artifacts/${artifact.id}/edit`">
|
||||
@@ -116,10 +116,6 @@ watch(
|
||||
<div v-if="detailTab === 'details'" class="detail-grid">
|
||||
<DetailSection :title="t('common.details')">
|
||||
<dl class="entity-profile-facts">
|
||||
<div>
|
||||
<dt>{{ t('pages.ancientArtifacts.displayId') }}</dt>
|
||||
<dd>#{{ artifact.displayId }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>{{ t('pages.ancientArtifacts.category') }}</dt>
|
||||
<dd>{{ artifact.category.name }}</dd>
|
||||
|
||||
@@ -36,7 +36,6 @@ const busy = ref(false);
|
||||
const message = ref('');
|
||||
const creatingSelect = ref('');
|
||||
const artifactForm = ref({
|
||||
displayId: 1,
|
||||
name: '',
|
||||
details: '',
|
||||
translations: {} as TranslationMap,
|
||||
@@ -98,7 +97,6 @@ async function loadEditor() {
|
||||
if (isEditing.value) {
|
||||
const artifact = await api.ancientArtifactDetail(routeId.value);
|
||||
artifactForm.value = {
|
||||
displayId: artifact.displayId,
|
||||
name: artifact.baseName ?? artifact.name,
|
||||
details: artifact.baseDetails ?? artifact.details,
|
||||
translations: artifact.translations ?? {},
|
||||
@@ -142,7 +140,6 @@ async function saveArtifact() {
|
||||
|
||||
try {
|
||||
const payload: AncientArtifactPayload = {
|
||||
displayId: artifactForm.value.displayId,
|
||||
name: artifactNameForSave(),
|
||||
details: artifactForm.value.details,
|
||||
translations: artifactForm.value.translations,
|
||||
@@ -190,11 +187,6 @@ onMounted(() => {
|
||||
required
|
||||
/>
|
||||
|
||||
<div class="field">
|
||||
<label for="artifact-display-id">{{ t('pages.ancientArtifacts.displayId') }}</label>
|
||||
<input id="artifact-display-id" v-model.number="artifactForm.displayId" type="number" min="1" required />
|
||||
</div>
|
||||
|
||||
<TranslationFields
|
||||
id-prefix="artifact-details"
|
||||
v-model:base-value="artifactForm.details"
|
||||
|
||||
@@ -126,7 +126,7 @@ watch(artifactQuery, loadArtifacts);
|
||||
<EntityCard
|
||||
v-for="artifact in artifacts"
|
||||
:key="artifact.id"
|
||||
:title="`#${artifact.displayId} ${artifact.name}`"
|
||||
:title="artifact.name"
|
||||
:subtitle="artifact.category.name"
|
||||
:to="`/ancient-artifacts/${artifact.id}`"
|
||||
:icon="iconArtifact"
|
||||
|
||||
@@ -74,7 +74,7 @@ const dishCategoryModalTitle = computed(() =>
|
||||
);
|
||||
const dishModalTitle = computed(() => (dishForm.value.id ? t('pages.dish.editDish') : t('pages.dish.newDish')));
|
||||
const itemSelectOptions = computed<TagsSelectOption[]>(() =>
|
||||
items.value.map((item) => ({ id: item.id, name: item.name, label: `#${item.displayId} ${item.name}` }))
|
||||
items.value.map((item) => ({ id: item.id, name: item.name }))
|
||||
);
|
||||
const optionalItemSelectOptions = computed<TagsSelectOption[]>(() => [{ id: '', name: t('common.none') }, ...itemSelectOptions.value]);
|
||||
const categorySelectOptions = computed<TagsSelectOption[]>(() => categories.value.map((category) => ({ id: category.id, name: category.name })));
|
||||
@@ -373,7 +373,7 @@ onMounted(loadPage);
|
||||
<div>
|
||||
<dt>{{ t('pages.dish.cookware') }}</dt>
|
||||
<dd>
|
||||
<RouterLink :to="`/items/${activeCategory.cookware.id}`">#{{ activeCategory.cookware.displayId }} {{ activeCategory.cookware.name }}</RouterLink>
|
||||
<RouterLink :to="`/items/${activeCategory.cookware.id}`">{{ activeCategory.cookware.name }}</RouterLink>
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
@@ -383,7 +383,7 @@ onMounted(loadPage);
|
||||
<div>
|
||||
<dt>{{ t('pages.dish.mainMaterial') }}</dt>
|
||||
<dd>
|
||||
<RouterLink :to="`/items/${activeCategory.mainMaterial.id}`">#{{ activeCategory.mainMaterial.displayId }} {{ activeCategory.mainMaterial.name }}</RouterLink>
|
||||
<RouterLink :to="`/items/${activeCategory.mainMaterial.id}`">{{ activeCategory.mainMaterial.name }}</RouterLink>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
@@ -411,7 +411,7 @@ onMounted(loadPage);
|
||||
<Icon v-else :icon="iconItem" class="entity-card__icon" aria-hidden="true" />
|
||||
</RouterLink>
|
||||
<div class="dish-card__content">
|
||||
<RouterLink class="dish-card__title" :to="`/items/${dish.item.id}`">#{{ dish.item.displayId }} {{ dish.item.name }}</RouterLink>
|
||||
<RouterLink class="dish-card__title" :to="`/items/${dish.item.id}`">{{ dish.item.name }}</RouterLink>
|
||||
<div class="dish-card__meta">
|
||||
<span>{{ dish.flavor.name }}</span>
|
||||
<span v-if="dish.pokemonSkill">{{ dish.pokemonSkill.name }}</span>
|
||||
|
||||
@@ -149,7 +149,7 @@ watch(
|
||||
</div>
|
||||
</section>
|
||||
<section v-else class="page-stack">
|
||||
<PageHeader :title="`#${item.displayId} ${item.name}`" :subtitle="itemSubtitle">
|
||||
<PageHeader :title="item.name" :subtitle="itemSubtitle">
|
||||
<template #kicker>{{ detailKicker }}</template>
|
||||
<template #actions>
|
||||
<RouterLink v-if="canUpdateItem" class="ui-button ui-button--primary ui-button--small" :to="`/items/${item.id}/edit`">
|
||||
@@ -182,10 +182,6 @@ watch(
|
||||
<div class="entity-profile-main">
|
||||
<section class="detail-section entity-profile-overview" :aria-label="t('common.details')">
|
||||
<dl class="entity-profile-facts">
|
||||
<div>
|
||||
<dt>{{ t('pages.items.displayId') }}</dt>
|
||||
<dd>#{{ item.displayId }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>{{ t('pages.items.category') }}</dt>
|
||||
<dd>{{ item.category.name }}</dd>
|
||||
|
||||
@@ -36,7 +36,6 @@ const busy = ref(false);
|
||||
const message = ref('');
|
||||
const creatingSelect = ref('');
|
||||
const itemForm = ref({
|
||||
displayId: 1,
|
||||
name: '',
|
||||
details: '',
|
||||
translations: {} as TranslationMap,
|
||||
@@ -117,7 +116,6 @@ async function loadEditor() {
|
||||
if (isEditing.value) {
|
||||
const item = await api.itemDetail(routeId.value);
|
||||
itemForm.value = {
|
||||
displayId: item.displayId,
|
||||
name: item.baseName ?? item.name,
|
||||
details: item.baseDetails ?? item.details,
|
||||
translations: item.translations ?? {},
|
||||
@@ -173,7 +171,6 @@ async function saveItem() {
|
||||
|
||||
try {
|
||||
const payload: ItemPayload = {
|
||||
displayId: itemForm.value.displayId,
|
||||
name: itemNameForSave(),
|
||||
details: itemForm.value.details,
|
||||
translations: itemForm.value.translations,
|
||||
@@ -226,11 +223,6 @@ onMounted(() => {
|
||||
required
|
||||
/>
|
||||
|
||||
<div class="field">
|
||||
<label for="item-display-id">{{ t('pages.items.displayId') }}</label>
|
||||
<input id="item-display-id" v-model.number="itemForm.displayId" type="number" min="1" required />
|
||||
</div>
|
||||
|
||||
<TranslationFields
|
||||
id-prefix="item-details"
|
||||
v-model:base-value="itemForm.details"
|
||||
|
||||
@@ -145,7 +145,7 @@ watch(itemQuery, loadItems);
|
||||
<EntityCard
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
:title="`#${item.displayId} ${item.name}`"
|
||||
:title="item.name"
|
||||
:subtitle="item.category.name"
|
||||
:to="`/items/${item.id}`"
|
||||
:icon="iconItem"
|
||||
|
||||
@@ -114,7 +114,7 @@ watch(
|
||||
</div>
|
||||
</section>
|
||||
<section v-else class="page-stack">
|
||||
<PageHeader :title="`#${recipe.item.displayId} ${recipe.name}`" :subtitle="recipeSubtitle">
|
||||
<PageHeader :title="recipe.name" :subtitle="recipeSubtitle">
|
||||
<template #kicker>{{ t('pages.recipes.detailKicker') }}</template>
|
||||
<template #actions>
|
||||
<RouterLink v-if="canUpdateRecipe" class="ui-button ui-button--primary ui-button--small" :to="`/recipes/${recipe.id}/edit`">
|
||||
@@ -145,7 +145,7 @@ watch(
|
||||
<Icon :icon="iconRecipe" class="entity-card__icon" aria-hidden="true" />
|
||||
</span>
|
||||
</RouterLink>
|
||||
<RouterLink class="entity-profile-title-link" :to="`/items/${recipe.item.id}`">#{{ recipe.item.displayId }} {{ recipe.item.name }}</RouterLink>
|
||||
<RouterLink class="entity-profile-title-link" :to="`/items/${recipe.item.id}`">{{ recipe.item.name }}</RouterLink>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ watch(itemQuery, loadItems);
|
||||
<EntityCard
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
:title="`#${item.displayId} ${item.name}`"
|
||||
:title="item.name"
|
||||
:subtitle="item.category.name"
|
||||
:to="recipeTarget(item)"
|
||||
:icon="itemIcon(item)"
|
||||
|
||||
@@ -245,7 +245,7 @@ export const systemWordingMessages = {
|
||||
},
|
||||
eventItems: {
|
||||
title: 'Event Items',
|
||||
description: 'Browse limited event items with their own Display IDs and shared item categories.'
|
||||
description: 'Browse limited event items with shared item categories and custom ordering.'
|
||||
},
|
||||
ancientArtifacts: {
|
||||
title: 'Ancient Artifacts',
|
||||
@@ -687,7 +687,6 @@ export const systemWordingMessages = {
|
||||
loadingList: 'Loading item list',
|
||||
loadingDetail: 'Loading item detail',
|
||||
loadingEdit: 'Loading item editor',
|
||||
displayId: 'Display ID',
|
||||
description: 'Description',
|
||||
category: 'Category',
|
||||
usage: 'Usage',
|
||||
@@ -724,14 +723,13 @@ export const systemWordingMessages = {
|
||||
detailKicker: 'Ancient Artifact Detail',
|
||||
detailSubtitle: 'Ancient Artifact detail',
|
||||
editKicker: 'Ancient Artifact Edit',
|
||||
editSubtitle: 'Maintain Ancient Artifact Display ID, image, description, category, tags, and translations.',
|
||||
editSubtitle: 'Maintain Ancient Artifact image, description, category, tags, and translations.',
|
||||
newTitle: 'New Ancient Artifact',
|
||||
editTitle: 'Edit {name}',
|
||||
fallbackName: 'Ancient Artifact',
|
||||
loadingList: 'Loading Ancient Artifact list',
|
||||
loadingDetail: 'Loading Ancient Artifact detail',
|
||||
loadingEdit: 'Loading Ancient Artifact editor',
|
||||
displayId: 'Display ID',
|
||||
description: 'Description',
|
||||
category: 'Category',
|
||||
tags: 'Tags',
|
||||
@@ -1311,11 +1309,9 @@ export const systemWordingMessages = {
|
||||
environmentRequired: 'Ideal Habitat is required',
|
||||
skillNoDrop: 'This speciality cannot have a drop item',
|
||||
habitatNameRequired: 'Habitat name is required',
|
||||
itemDisplayIdRequired: 'Item Display ID is required',
|
||||
usageRequired: 'Usage is required',
|
||||
itemNameRequired: 'Item name is required',
|
||||
categoryRequired: 'Category is required',
|
||||
artifactDisplayIdRequired: 'Ancient Artifact Display ID is required',
|
||||
artifactNameRequired: 'Ancient Artifact name is required',
|
||||
recipeFreeWithRecipe: 'An item with a recipe cannot be marked as recipe-free',
|
||||
itemRequired: 'Item is required',
|
||||
@@ -1600,7 +1596,7 @@ export const systemWordingMessages = {
|
||||
},
|
||||
eventItems: {
|
||||
title: 'Event Items',
|
||||
description: '浏览限时活动物品,并维护独立的 Display ID 与共享分类。'
|
||||
description: '浏览限时活动物品、共享分类与自定义排序。'
|
||||
},
|
||||
ancientArtifacts: {
|
||||
title: 'Ancient Artifacts',
|
||||
@@ -2022,7 +2018,6 @@ export const systemWordingMessages = {
|
||||
loadingList: '正在加载列表',
|
||||
loadingDetail: '正在加载物品详情',
|
||||
loadingEdit: '正在加载物品编辑内容',
|
||||
displayId: 'Display ID',
|
||||
description: '介绍',
|
||||
category: '分类',
|
||||
usage: '用途',
|
||||
@@ -2059,14 +2054,13 @@ export const systemWordingMessages = {
|
||||
detailKicker: 'Ancient Artifact Detail',
|
||||
detailSubtitle: 'Ancient Artifact 详情',
|
||||
editKicker: 'Ancient Artifact Edit',
|
||||
editSubtitle: '维护 Ancient Artifact Display ID、图片、介绍、分类、标签和翻译。',
|
||||
editSubtitle: '维护 Ancient Artifact 图片、介绍、分类、标签和翻译。',
|
||||
newTitle: '新增 Ancient Artifact',
|
||||
editTitle: '编辑 {name}',
|
||||
fallbackName: 'Ancient Artifact',
|
||||
loadingList: '正在加载 Ancient Artifact 列表',
|
||||
loadingDetail: '正在加载 Ancient Artifact 详情',
|
||||
loadingEdit: '正在加载 Ancient Artifact 编辑内容',
|
||||
displayId: 'Display ID',
|
||||
description: '介绍',
|
||||
category: '分类',
|
||||
tags: '标签',
|
||||
@@ -2644,14 +2638,12 @@ export const systemWordingMessages = {
|
||||
heightNonNegative: '身高必须是不小于 0 的数字',
|
||||
weightNonNegative: '体重必须是不小于 0 的数字',
|
||||
environmentRequired: '请选择喜欢的环境',
|
||||
skillNoDrop: '这个特长不能设置掉落物',
|
||||
habitatNameRequired: '请输入栖息地名称',
|
||||
itemDisplayIdRequired: '请输入物品 Display ID',
|
||||
usageRequired: '请选择用途',
|
||||
itemNameRequired: '请输入物品名称',
|
||||
categoryRequired: '请选择分类',
|
||||
artifactDisplayIdRequired: '请输入 Ancient Artifact Display ID',
|
||||
artifactNameRequired: '请输入 Ancient Artifact 名称',
|
||||
skillNoDrop: '这个特长不能设置掉落物',
|
||||
habitatNameRequired: '请输入栖息地名称',
|
||||
usageRequired: '请选择用途',
|
||||
itemNameRequired: '请输入物品名称',
|
||||
categoryRequired: '请选择分类',
|
||||
artifactNameRequired: '请输入 Ancient Artifact 名称',
|
||||
recipeFreeWithRecipe: '已有材料单的物品不能标记为无材料单',
|
||||
itemRequired: '请选择物品',
|
||||
recipeFreeItem: '这个物品已标记为无材料单',
|
||||
|
||||
Reference in New Issue
Block a user