资源批量添加
This commit is contained in:
parent
cf291546de
commit
4eb2554c20
@ -26,11 +26,13 @@ import { addPropsSource } from '#/api/legacy/props';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
BADGE_DISPLAY_TYPE_OPTIONS,
|
BADGE_DISPLAY_TYPE_OPTIONS,
|
||||||
|
getPropsTypeName,
|
||||||
PROPS_RESOURCE_CONFIG_TYPES,
|
PROPS_RESOURCE_CONFIG_TYPES,
|
||||||
} from '../shared';
|
} from '../shared';
|
||||||
|
|
||||||
type AssetKind = 'cover' | 'expand' | 'source';
|
type AssetKind = 'cover' | 'expand' | 'source';
|
||||||
type RowStatus = 'error' | 'ready' | 'saved' | 'saving' | 'uploading';
|
type RowStatus = 'error' | 'ready' | 'saved' | 'saving' | 'uploading';
|
||||||
|
type StructuredAssetKind = 'cover' | 'source';
|
||||||
|
|
||||||
interface BatchRow {
|
interface BatchRow {
|
||||||
adminFree: boolean;
|
adminFree: boolean;
|
||||||
@ -55,6 +57,25 @@ interface BatchRow {
|
|||||||
sourceUploading: boolean;
|
sourceUploading: boolean;
|
||||||
sourceUrl: string;
|
sourceUrl: string;
|
||||||
status: RowStatus;
|
status: RowStatus;
|
||||||
|
type: string;
|
||||||
|
typeTouched: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FindRowOptions {
|
||||||
|
adminFree?: boolean;
|
||||||
|
amount?: number | string;
|
||||||
|
amountTouched?: boolean;
|
||||||
|
code?: string;
|
||||||
|
type?: string;
|
||||||
|
typeTouched?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StructuredResourceFile {
|
||||||
|
amount: number;
|
||||||
|
assetKind: StructuredAssetKind;
|
||||||
|
code: string;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@ -97,23 +118,112 @@ const badgeDisplayTypeOptions = BADGE_DISPLAY_TYPE_OPTIONS.map((item) => ({
|
|||||||
value: item.value as any,
|
value: item.value as any,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const isImageSourceType = computed(() =>
|
const STRUCTURED_RESOURCE_TYPE_MAP: Record<string, string> = {
|
||||||
['CHAT_BUBBLE', 'LAYOUT', 'THEME'].includes(batchForm.type),
|
勋章: 'BADGE',
|
||||||
|
坐骑: 'RIDE',
|
||||||
|
头像框: 'AVATAR_FRAME',
|
||||||
|
};
|
||||||
|
const STRUCTURED_ASSET_KIND_MAP: Record<string, StructuredAssetKind> = {
|
||||||
|
animation: 'source',
|
||||||
|
cover: 'cover',
|
||||||
|
};
|
||||||
|
const RESOURCE_NAME_TRANSLATION_ENTRIES = ([
|
||||||
|
['头像框', 'avatar frame'],
|
||||||
|
['座驾', 'ride'],
|
||||||
|
['坐骑', 'mount'],
|
||||||
|
['勋章', 'badge'],
|
||||||
|
['徽章', 'badge'],
|
||||||
|
['管理员', 'admin'],
|
||||||
|
['圣诞', 'christmas'],
|
||||||
|
['新年', 'new year'],
|
||||||
|
['情人节', 'valentine'],
|
||||||
|
['万圣节', 'halloween'],
|
||||||
|
['锦鲤', 'koi'],
|
||||||
|
['熊猫', 'panda'],
|
||||||
|
['独角兽', 'unicorn'],
|
||||||
|
['天使', 'angel'],
|
||||||
|
['恶魔', 'devil'],
|
||||||
|
['皇冠', 'crown'],
|
||||||
|
['国王', 'king'],
|
||||||
|
['女王', 'queen'],
|
||||||
|
['玫瑰', 'rose'],
|
||||||
|
['星光', 'starlight'],
|
||||||
|
['星星', 'star'],
|
||||||
|
['月亮', 'moon'],
|
||||||
|
['太阳', 'sun'],
|
||||||
|
['彩虹', 'rainbow'],
|
||||||
|
['火焰', 'flame'],
|
||||||
|
['冰雪', 'snow'],
|
||||||
|
['蓝色', 'blue'],
|
||||||
|
['红色', 'red'],
|
||||||
|
['紫色', 'purple'],
|
||||||
|
['粉色', 'pink'],
|
||||||
|
['金色', 'gold'],
|
||||||
|
['银色', 'silver'],
|
||||||
|
['黑色', 'black'],
|
||||||
|
['白色', 'white'],
|
||||||
|
['绿色', 'green'],
|
||||||
|
['黄色', 'yellow'],
|
||||||
|
['钻石', 'diamond'],
|
||||||
|
['水晶', 'crystal'],
|
||||||
|
['幸运', 'lucky'],
|
||||||
|
['浪漫', 'romantic'],
|
||||||
|
['荣耀', 'glory'],
|
||||||
|
['守护', 'guard'],
|
||||||
|
['贵族', 'noble'],
|
||||||
|
['梦幻', 'dream'],
|
||||||
|
['闪耀', 'shining'],
|
||||||
|
['限定', 'limited'],
|
||||||
|
['豪华', 'deluxe'],
|
||||||
|
['高级', 'premium'],
|
||||||
|
['经典', 'classic'],
|
||||||
|
['热气球', 'hot air balloon'],
|
||||||
|
['跑车', 'sports car'],
|
||||||
|
['飞船', 'spaceship'],
|
||||||
|
['游艇', 'yacht'],
|
||||||
|
['摩托', 'motorcycle'],
|
||||||
|
['龙', 'dragon'],
|
||||||
|
['凤', 'phoenix'],
|
||||||
|
['虎', 'tiger'],
|
||||||
|
['兔', 'rabbit'],
|
||||||
|
['猫', 'cat'],
|
||||||
|
['狗', 'dog'],
|
||||||
|
['鱼', 'fish'],
|
||||||
|
] as Array<[string, string]>).toSorted(
|
||||||
|
(current, next) => next[0].length - current[0].length,
|
||||||
);
|
);
|
||||||
const isAmountRequired = computed(
|
|
||||||
() => !['CUSTOMIZE', 'FRAGMENTS'].includes(batchForm.type),
|
function isImageSourceTypeByType(type: string) {
|
||||||
|
return ['CHAT_BUBBLE', 'LAYOUT', 'THEME'].includes(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAmountRequiredByType(type: string) {
|
||||||
|
return !['CUSTOMIZE', 'FRAGMENTS'].includes(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSourceRequiredByType(type: string) {
|
||||||
|
return !['BADGE', 'CUSTOMIZE', 'FRAGMENTS'].includes(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showExpandUploadByType(type: string) {
|
||||||
|
return type === 'CHAT_BUBBLE';
|
||||||
|
}
|
||||||
|
|
||||||
|
const isImageSourceType = computed(() => isImageSourceTypeByType(batchForm.type));
|
||||||
|
const isAmountRequired = computed(() => isAmountRequiredByType(batchForm.type));
|
||||||
|
const showExpandUpload = computed(() => showExpandUploadByType(batchForm.type));
|
||||||
|
const hasExpandColumn = computed(
|
||||||
|
() =>
|
||||||
|
showExpandUpload.value
|
||||||
|
|| rows.value.some((row) => showExpandUploadByType(getRowType(row))),
|
||||||
);
|
);
|
||||||
const isSourceRequired = computed(
|
|
||||||
() => !['BADGE', 'CUSTOMIZE', 'FRAGMENTS'].includes(batchForm.type),
|
|
||||||
);
|
|
||||||
const showExpandUpload = computed(() => batchForm.type === 'CHAT_BUBBLE');
|
|
||||||
|
|
||||||
const columns = computed(() => {
|
const columns = computed(() => {
|
||||||
const baseColumns = [
|
const baseColumns = [
|
||||||
{ dataIndex: 'cover', key: 'cover', title: '封面', width: 116 },
|
{ dataIndex: 'cover', key: 'cover', title: '封面', width: 116 },
|
||||||
{ dataIndex: 'sourceUrl', key: 'sourceUrl', title: '资源', width: 180 },
|
{ dataIndex: 'sourceUrl', key: 'sourceUrl', title: '资源', width: 180 },
|
||||||
];
|
];
|
||||||
if (showExpandUpload.value) {
|
if (hasExpandColumn.value) {
|
||||||
baseColumns.push({
|
baseColumns.push({
|
||||||
dataIndex: 'expand',
|
dataIndex: 'expand',
|
||||||
key: 'expand',
|
key: 'expand',
|
||||||
@ -123,6 +233,7 @@ const columns = computed(() => {
|
|||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
...baseColumns,
|
...baseColumns,
|
||||||
|
{ dataIndex: 'type', key: 'type', title: '类型', width: 132 },
|
||||||
{ dataIndex: 'name', key: 'name', title: '名称', width: 180 },
|
{ dataIndex: 'name', key: 'name', title: '名称', width: 180 },
|
||||||
{ dataIndex: 'code', key: 'code', title: '编码', width: 180 },
|
{ dataIndex: 'code', key: 'code', title: '编码', width: 180 },
|
||||||
{ dataIndex: 'amount', key: 'amount', title: '底价', width: 116 },
|
{ dataIndex: 'amount', key: 'amount', title: '底价', width: 116 },
|
||||||
@ -228,6 +339,11 @@ watch(
|
|||||||
watch(
|
watch(
|
||||||
() => [batchForm.type, batchForm.sysOrigin, batchForm.badgeDisplayType],
|
() => [batchForm.type, batchForm.sysOrigin, batchForm.badgeDisplayType],
|
||||||
() => {
|
() => {
|
||||||
|
rows.value.forEach((row) => {
|
||||||
|
if (!row.typeTouched) {
|
||||||
|
row.type = batchForm.type;
|
||||||
|
}
|
||||||
|
});
|
||||||
refreshAllRows();
|
refreshAllRows();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -247,7 +363,33 @@ function normalizeBaseName(value: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function normalizeCode(value: string) {
|
function normalizeCode(value: string) {
|
||||||
return normalizeBaseName(value).replaceAll(/\s+/g, '_');
|
const baseName = normalizeBaseName(value);
|
||||||
|
const translated = translateResourceName(baseName);
|
||||||
|
return slugifyResourceCode(translated) || slugifyResourceCode(baseName) || 'resource';
|
||||||
|
}
|
||||||
|
|
||||||
|
function translateResourceName(value: string) {
|
||||||
|
let result = value.trim();
|
||||||
|
RESOURCE_NAME_TRANSLATION_ENTRIES.forEach(([source, target]) => {
|
||||||
|
result = result.replaceAll(source, ` ${target} `);
|
||||||
|
});
|
||||||
|
return [...result]
|
||||||
|
.map((char) => {
|
||||||
|
if (/[\u4E00-\u9FFF]/.test(char)) {
|
||||||
|
return ` u${char.codePointAt(0)?.toString(16) || ''} `;
|
||||||
|
}
|
||||||
|
return char;
|
||||||
|
})
|
||||||
|
.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function slugifyResourceCode(value: string) {
|
||||||
|
return value
|
||||||
|
.normalize('NFKC')
|
||||||
|
.replaceAll(/[^\d A-Za-z]+/g, ' ')
|
||||||
|
.trim()
|
||||||
|
.replaceAll(/\s+/g, '_')
|
||||||
|
.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPathFileName(path: string) {
|
function getPathFileName(path: string) {
|
||||||
@ -311,17 +453,93 @@ function getFileBaseName(file: File) {
|
|||||||
return normalizeBaseName(getPathFileName(getFilePath(file)));
|
return normalizeBaseName(getPathFileName(getFilePath(file)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function findOrCreateRow(baseName: string) {
|
function parseStructuredResourceFile(file: File): null | StructuredResourceFile {
|
||||||
const code = normalizeCode(baseName);
|
if (!isImageFile(file) && !isResourceFile(file)) {
|
||||||
const matched = rows.value.find((row) => row.code === code || row.name === baseName);
|
return null;
|
||||||
|
}
|
||||||
|
const fileName = getPathFileName(getFilePath(file));
|
||||||
|
const baseName = fileName.replace(/\.[^.]+$/, '').trim();
|
||||||
|
const parts = baseName
|
||||||
|
.split('_')
|
||||||
|
.map((part) => part.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
const type = STRUCTURED_RESOURCE_TYPE_MAP[parts[0] || ''];
|
||||||
|
const assetKind =
|
||||||
|
STRUCTURED_ASSET_KIND_MAP[String(parts[parts.length - 1] || '').toLowerCase()];
|
||||||
|
if (!type || !assetKind) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (assetKind === 'cover' && !isImageFile(file)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (type === 'BADGE') {
|
||||||
|
const name = parts.slice(1, -1).join('_').trim();
|
||||||
|
if (!name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
amount: 0,
|
||||||
|
assetKind,
|
||||||
|
code: normalizeCode(name),
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (parts.length < 5) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const amount = Number(parts[parts.length - 3]);
|
||||||
|
const name = parts.slice(1, -3).join('_').trim();
|
||||||
|
if (!name || !Number.isFinite(amount) || amount < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
amount: normalizeAmount(amount),
|
||||||
|
assetKind,
|
||||||
|
code: normalizeCode(name),
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRowType(row: BatchRow) {
|
||||||
|
return String(row.type || batchForm.type || '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function findOrCreateRow(baseName: string, options: FindRowOptions = {}) {
|
||||||
|
const name = baseName.trim() || 'resource';
|
||||||
|
const type = String(options.type || batchForm.type || '');
|
||||||
|
const code = options.code || normalizeCode(name);
|
||||||
|
const matched = rows.value.find(
|
||||||
|
(row) =>
|
||||||
|
getRowType(row) === type
|
||||||
|
&& (String(row.code || '') === code || String(row.name || '') === name),
|
||||||
|
);
|
||||||
if (matched) {
|
if (matched) {
|
||||||
|
if (options.adminFree !== undefined) {
|
||||||
|
matched.adminFree = options.adminFree;
|
||||||
|
}
|
||||||
|
if (options.amount !== undefined) {
|
||||||
|
matched.amount = normalizeAmount(options.amount);
|
||||||
|
matched.amountTouched = options.amountTouched ?? true;
|
||||||
|
}
|
||||||
|
if (options.code) {
|
||||||
|
matched.code = options.code;
|
||||||
|
}
|
||||||
|
if (options.type) {
|
||||||
|
matched.type = options.type;
|
||||||
|
matched.typeTouched = options.typeTouched ?? true;
|
||||||
|
}
|
||||||
matched.saved = false;
|
matched.saved = false;
|
||||||
return matched;
|
return matched;
|
||||||
}
|
}
|
||||||
const row: BatchRow = {
|
const row: BatchRow = {
|
||||||
adminFree: batchForm.adminFree,
|
adminFree: options.adminFree ?? batchForm.adminFree,
|
||||||
amount: normalizeAmount(batchForm.amount),
|
amount:
|
||||||
amountTouched: false,
|
options.amount === undefined
|
||||||
|
? normalizeAmount(batchForm.amount)
|
||||||
|
: normalizeAmount(options.amount),
|
||||||
|
amountTouched: options.amountTouched ?? false,
|
||||||
code,
|
code,
|
||||||
cover: '',
|
cover: '',
|
||||||
coverError: '',
|
coverError: '',
|
||||||
@ -333,7 +551,7 @@ function findOrCreateRow(baseName: string) {
|
|||||||
expandFileName: '',
|
expandFileName: '',
|
||||||
expandUploading: false,
|
expandUploading: false,
|
||||||
key: `batch-${Date.now()}-${sequence.value++}`,
|
key: `batch-${Date.now()}-${sequence.value++}`,
|
||||||
name: baseName,
|
name,
|
||||||
saved: false,
|
saved: false,
|
||||||
saving: false,
|
saving: false,
|
||||||
sourceError: '',
|
sourceError: '',
|
||||||
@ -341,6 +559,8 @@ function findOrCreateRow(baseName: string) {
|
|||||||
sourceUploading: false,
|
sourceUploading: false,
|
||||||
sourceUrl: '',
|
sourceUrl: '',
|
||||||
status: 'error',
|
status: 'error',
|
||||||
|
type,
|
||||||
|
typeTouched: options.typeTouched ?? false,
|
||||||
};
|
};
|
||||||
rows.value.push(row);
|
rows.value.push(row);
|
||||||
if (!activeRowKey.value) {
|
if (!activeRowKey.value) {
|
||||||
@ -419,6 +639,20 @@ async function uploadAsset(
|
|||||||
function processFiles(files: File[]) {
|
function processFiles(files: File[]) {
|
||||||
let accepted = 0;
|
let accepted = 0;
|
||||||
files.forEach((file) => {
|
files.forEach((file) => {
|
||||||
|
const structuredFile = parseStructuredResourceFile(file);
|
||||||
|
if (structuredFile) {
|
||||||
|
const row = findOrCreateRow(structuredFile.name, {
|
||||||
|
adminFree: false,
|
||||||
|
amount: structuredFile.amount,
|
||||||
|
amountTouched: true,
|
||||||
|
code: structuredFile.code,
|
||||||
|
type: structuredFile.type,
|
||||||
|
typeTouched: true,
|
||||||
|
});
|
||||||
|
setRowAsset(row, structuredFile.assetKind, file);
|
||||||
|
accepted += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
const kind = classifyFile(file);
|
const kind = classifyFile(file);
|
||||||
if (!kind) {
|
if (!kind) {
|
||||||
return;
|
return;
|
||||||
@ -515,7 +749,8 @@ function getRowErrors(
|
|||||||
if (!batchForm.sysOrigin) {
|
if (!batchForm.sysOrigin) {
|
||||||
errors.push('请选择系统');
|
errors.push('请选择系统');
|
||||||
}
|
}
|
||||||
if (!batchForm.type) {
|
const rowType = getRowType(row);
|
||||||
|
if (!rowType) {
|
||||||
errors.push('请选择类型');
|
errors.push('请选择类型');
|
||||||
}
|
}
|
||||||
if (!String(row.name || '').trim()) {
|
if (!String(row.name || '').trim()) {
|
||||||
@ -542,14 +777,14 @@ function getRowErrors(
|
|||||||
if (!row.cover && !row.coverUploading) {
|
if (!row.cover && !row.coverUploading) {
|
||||||
errors.push('缺少封面');
|
errors.push('缺少封面');
|
||||||
}
|
}
|
||||||
if (isSourceRequired.value && !row.sourceUrl && !row.sourceUploading) {
|
if (isSourceRequiredByType(rowType) && !row.sourceUrl && !row.sourceUploading) {
|
||||||
errors.push('缺少资源');
|
errors.push('缺少资源');
|
||||||
}
|
}
|
||||||
if (showExpandUpload.value && !row.expand && !row.expandUploading) {
|
if (showExpandUploadByType(rowType) && !row.expand && !row.expandUploading) {
|
||||||
errors.push('缺少 Android 资源');
|
errors.push('缺少 Android 资源');
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
isAmountRequired.value
|
isAmountRequiredByType(rowType)
|
||||||
&& (!Number.isFinite(Number(row.amount)) || Number(row.amount) < 0)
|
&& (!Number.isFinite(Number(row.amount)) || Number(row.amount) < 0)
|
||||||
) {
|
) {
|
||||||
errors.push('底价不正确');
|
errors.push('底价不正确');
|
||||||
@ -594,6 +829,13 @@ function markAmountTouched(record: Record<string, any>) {
|
|||||||
refreshAllRows();
|
refreshAllRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function markTypeTouched(record: Record<string, any>) {
|
||||||
|
const row = record as BatchRow;
|
||||||
|
row.typeTouched = true;
|
||||||
|
row.saved = false;
|
||||||
|
refreshAllRows();
|
||||||
|
}
|
||||||
|
|
||||||
function markRowEdited(record: Record<string, any>) {
|
function markRowEdited(record: Record<string, any>) {
|
||||||
const row = record as BatchRow;
|
const row = record as BatchRow;
|
||||||
row.saved = false;
|
row.saved = false;
|
||||||
@ -722,17 +964,18 @@ function buildBadgeExpand() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function buildPayload(row: BatchRow) {
|
function buildPayload(row: BatchRow) {
|
||||||
|
const rowType = getRowType(row);
|
||||||
return {
|
return {
|
||||||
adminFree: row.adminFree,
|
adminFree: row.adminFree,
|
||||||
amount: isAmountRequired.value ? normalizeAmount(row.amount) : 0,
|
amount: isAmountRequiredByType(rowType) ? normalizeAmount(row.amount) : 0,
|
||||||
code: String(row.code || '').trim(),
|
code: String(row.code || '').trim(),
|
||||||
cover: row.cover,
|
cover: row.cover,
|
||||||
expand: batchForm.type === 'BADGE' ? buildBadgeExpand() : row.expand,
|
expand: rowType === 'BADGE' ? buildBadgeExpand() : row.expand,
|
||||||
id: '',
|
id: '',
|
||||||
name: String(row.name || '').trim(),
|
name: String(row.name || '').trim(),
|
||||||
sourceUrl: row.sourceUrl,
|
sourceUrl: row.sourceUrl,
|
||||||
sysOrigin: batchForm.sysOrigin,
|
sysOrigin: batchForm.sysOrigin,
|
||||||
type: batchForm.type,
|
type: rowType,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -907,7 +1150,7 @@ function customRow(record: Record<string, any>) {
|
|||||||
@drop.prevent="handleDrop"
|
@drop.prevent="handleDrop"
|
||||||
>
|
>
|
||||||
<div class="dropzone-title">拖拽文件到这里</div>
|
<div class="dropzone-title">拖拽文件到这里</div>
|
||||||
<div class="dropzone-desc">封面和资源按文件名自动配对</div>
|
<div class="dropzone-desc">选择文件夹后按命名规则自动配对</div>
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
<Button type="primary" @click.stop="fileInputRef?.click()">
|
<Button type="primary" @click.stop="fileInputRef?.click()">
|
||||||
选择文件
|
选择文件
|
||||||
@ -918,9 +1161,10 @@ function customRow(record: Record<string, any>) {
|
|||||||
|
|
||||||
<div class="import-rules">
|
<div class="import-rules">
|
||||||
<div class="side-title">识别规则</div>
|
<div class="side-title">识别规则</div>
|
||||||
<div class="rule-item">cover/ 或文件名 _cover 识别为封面</div>
|
<div class="rule-item">坐骑_物品名_价格_1天_cover/animation</div>
|
||||||
<div class="rule-item">resource/、source/ 或 svga/pag/mp4/zip 识别为资源</div>
|
<div class="rule-item">头像框_物品名_价格_1天_cover/animation</div>
|
||||||
<div class="rule-item">聊天气泡 android/ 或 _android 识别为 Android 资源</div>
|
<div class="rule-item">勋章_物品名_cover/animation</div>
|
||||||
|
<div class="rule-item">cover 写入封面,animation 写入动态图资源</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="import-progress">
|
<div class="import-progress">
|
||||||
@ -1012,6 +1256,16 @@ function customRow(record: Record<string, any>) {
|
|||||||
<div class="file-name">{{ record.expandFileName || '-' }}</div>
|
<div class="file-name">{{ record.expandFileName || '-' }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="column.key === 'type'">
|
||||||
|
<Select
|
||||||
|
v-model:value="record.type"
|
||||||
|
option-label-prop="label"
|
||||||
|
:options="propsTypeOptions"
|
||||||
|
size="small"
|
||||||
|
style="width: 118px"
|
||||||
|
@change="markTypeTouched(record)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
<template v-else-if="column.key === 'name'">
|
<template v-else-if="column.key === 'name'">
|
||||||
<Input
|
<Input
|
||||||
v-model:value="record.name"
|
v-model:value="record.name"
|
||||||
@ -1029,7 +1283,7 @@ function customRow(record: Record<string, any>) {
|
|||||||
<template v-else-if="column.key === 'amount'">
|
<template v-else-if="column.key === 'amount'">
|
||||||
<InputNumber
|
<InputNumber
|
||||||
v-model:value="record.amount"
|
v-model:value="record.amount"
|
||||||
:disabled="!isAmountRequired"
|
:disabled="!isAmountRequiredByType(record.type)"
|
||||||
:min="0"
|
:min="0"
|
||||||
size="small"
|
size="small"
|
||||||
style="width: 96px"
|
style="width: 96px"
|
||||||
@ -1070,10 +1324,13 @@ function customRow(record: Record<string, any>) {
|
|||||||
<div v-else class="preview-empty">未上传封面</div>
|
<div v-else class="preview-empty">未上传封面</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="preview-name">{{ activeRow.name || '-' }}</div>
|
<div class="preview-name">{{ activeRow.name || '-' }}</div>
|
||||||
|
<div class="preview-meta">
|
||||||
|
类型:{{ getPropsTypeName(getRowType(activeRow)) }}
|
||||||
|
</div>
|
||||||
<div class="preview-meta">编码:{{ activeRow.code || '-' }}</div>
|
<div class="preview-meta">编码:{{ activeRow.code || '-' }}</div>
|
||||||
<div class="preview-meta">封面:{{ activeRow.coverFileName || '-' }}</div>
|
<div class="preview-meta">封面:{{ activeRow.coverFileName || '-' }}</div>
|
||||||
<div class="preview-meta">资源:{{ activeRow.sourceFileName || '-' }}</div>
|
<div class="preview-meta">资源:{{ activeRow.sourceFileName || '-' }}</div>
|
||||||
<div v-if="showExpandUpload" class="preview-meta">
|
<div v-if="showExpandUploadByType(getRowType(activeRow))" class="preview-meta">
|
||||||
Android:{{ activeRow.expandFileName || '-' }}
|
Android:{{ activeRow.expandFileName || '-' }}
|
||||||
</div>
|
</div>
|
||||||
<div class="side-title side-title--spaced">校验结果</div>
|
<div class="side-title side-title--spaced">校验结果</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user