feat: 添加文件上传组件,更新表单字段,优化描述输入逻辑
This commit is contained in:
8
components.d.ts
vendored
8
components.d.ts
vendored
@@ -51,6 +51,7 @@ declare module 'vue' {
|
|||||||
IonTabButton: typeof import('@ionic/vue')['IonTabButton']
|
IonTabButton: typeof import('@ionic/vue')['IonTabButton']
|
||||||
IonTabs: typeof import('@ionic/vue')['IonTabs']
|
IonTabs: typeof import('@ionic/vue')['IonTabs']
|
||||||
IonText: typeof import('@ionic/vue')['IonText']
|
IonText: typeof import('@ionic/vue')['IonText']
|
||||||
|
IonTextarea: typeof import('@ionic/vue')['IonTextarea']
|
||||||
IonTitle: typeof import('@ionic/vue')['IonTitle']
|
IonTitle: typeof import('@ionic/vue')['IonTitle']
|
||||||
IonToolbar: typeof import('@ionic/vue')['IonToolbar']
|
IonToolbar: typeof import('@ionic/vue')['IonToolbar']
|
||||||
LayoutDefault: typeof import('./src/components/layout/default.vue')['default']
|
LayoutDefault: typeof import('./src/components/layout/default.vue')['default']
|
||||||
@@ -62,12 +63,15 @@ declare module 'vue' {
|
|||||||
UiCollapse: typeof import('./src/components/ui/collapse/index.vue')['default']
|
UiCollapse: typeof import('./src/components/ui/collapse/index.vue')['default']
|
||||||
UiDatetime: typeof import('./src/components/ui/datetime/index.vue')['default']
|
UiDatetime: typeof import('./src/components/ui/datetime/index.vue')['default']
|
||||||
UiDivider: typeof import('./src/components/ui/divider/index.vue')['default']
|
UiDivider: typeof import('./src/components/ui/divider/index.vue')['default']
|
||||||
|
UiFileUpload: typeof import('./src/components/ui/file-upload/index.vue')['default']
|
||||||
UiInput: typeof import('./src/components/ui/input/index.vue')['default']
|
UiInput: typeof import('./src/components/ui/input/index.vue')['default']
|
||||||
UiInputLabel: typeof import('./src/components/ui/input-label/index.vue')['default']
|
UiInputLabel: typeof import('./src/components/ui/input-label/index.vue')['default']
|
||||||
UiResult: typeof import('./src/components/ui/result/index.vue')['default']
|
UiResult: typeof import('./src/components/ui/result/index.vue')['default']
|
||||||
UiTabPane: typeof import('./src/components/ui/tab-pane/index.vue')['default']
|
UiTabPane: typeof import('./src/components/ui/tab-pane/index.vue')['default']
|
||||||
UiTabs: typeof import('./src/components/ui/tabs/index.vue')['default']
|
UiTabs: typeof import('./src/components/ui/tabs/index.vue')['default']
|
||||||
UiTag: typeof import('./src/components/ui/tag/index.vue')['default']
|
UiTag: typeof import('./src/components/ui/tag/index.vue')['default']
|
||||||
|
UiTextarea: typeof import('./src/components/ui/textarea/index.vue')['default']
|
||||||
|
UiTextareaLabel: typeof import('./src/components/ui/textarea-label/index.vue')['default']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,6 +116,7 @@ declare global {
|
|||||||
const IonTabButton: typeof import('@ionic/vue')['IonTabButton']
|
const IonTabButton: typeof import('@ionic/vue')['IonTabButton']
|
||||||
const IonTabs: typeof import('@ionic/vue')['IonTabs']
|
const IonTabs: typeof import('@ionic/vue')['IonTabs']
|
||||||
const IonText: typeof import('@ionic/vue')['IonText']
|
const IonText: typeof import('@ionic/vue')['IonText']
|
||||||
|
const IonTextarea: typeof import('@ionic/vue')['IonTextarea']
|
||||||
const IonTitle: typeof import('@ionic/vue')['IonTitle']
|
const IonTitle: typeof import('@ionic/vue')['IonTitle']
|
||||||
const IonToolbar: typeof import('@ionic/vue')['IonToolbar']
|
const IonToolbar: typeof import('@ionic/vue')['IonToolbar']
|
||||||
const LayoutDefault: typeof import('./src/components/layout/default.vue')['default']
|
const LayoutDefault: typeof import('./src/components/layout/default.vue')['default']
|
||||||
@@ -123,10 +128,13 @@ declare global {
|
|||||||
const UiCollapse: typeof import('./src/components/ui/collapse/index.vue')['default']
|
const UiCollapse: typeof import('./src/components/ui/collapse/index.vue')['default']
|
||||||
const UiDatetime: typeof import('./src/components/ui/datetime/index.vue')['default']
|
const UiDatetime: typeof import('./src/components/ui/datetime/index.vue')['default']
|
||||||
const UiDivider: typeof import('./src/components/ui/divider/index.vue')['default']
|
const UiDivider: typeof import('./src/components/ui/divider/index.vue')['default']
|
||||||
|
const UiFileUpload: typeof import('./src/components/ui/file-upload/index.vue')['default']
|
||||||
const UiInput: typeof import('./src/components/ui/input/index.vue')['default']
|
const UiInput: typeof import('./src/components/ui/input/index.vue')['default']
|
||||||
const UiInputLabel: typeof import('./src/components/ui/input-label/index.vue')['default']
|
const UiInputLabel: typeof import('./src/components/ui/input-label/index.vue')['default']
|
||||||
const UiResult: typeof import('./src/components/ui/result/index.vue')['default']
|
const UiResult: typeof import('./src/components/ui/result/index.vue')['default']
|
||||||
const UiTabPane: typeof import('./src/components/ui/tab-pane/index.vue')['default']
|
const UiTabPane: typeof import('./src/components/ui/tab-pane/index.vue')['default']
|
||||||
const UiTabs: typeof import('./src/components/ui/tabs/index.vue')['default']
|
const UiTabs: typeof import('./src/components/ui/tabs/index.vue')['default']
|
||||||
const UiTag: typeof import('./src/components/ui/tag/index.vue')['default']
|
const UiTag: typeof import('./src/components/ui/tag/index.vue')['default']
|
||||||
|
const UiTextarea: typeof import('./src/components/ui/textarea/index.vue')['default']
|
||||||
|
const UiTextareaLabel: typeof import('./src/components/ui/textarea-label/index.vue')['default']
|
||||||
}
|
}
|
||||||
248
src/components/ui/file-upload/index.vue
Normal file
248
src/components/ui/file-upload/index.vue
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
<script lang='ts' setup>
|
||||||
|
import { documentAttachOutline, trashOutline } from "ionicons/icons";
|
||||||
|
|
||||||
|
interface FileItem {
|
||||||
|
name: string;
|
||||||
|
size: number;
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<{
|
||||||
|
modelValue?: string[];
|
||||||
|
label?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
accept?: string;
|
||||||
|
multiple?: boolean;
|
||||||
|
maxSize?: number; // MB
|
||||||
|
maxFiles?: number;
|
||||||
|
}>(), {
|
||||||
|
modelValue: () => [],
|
||||||
|
accept: "*/*",
|
||||||
|
multiple: true,
|
||||||
|
maxSize: 10,
|
||||||
|
maxFiles: 5,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: "update:modelValue", value: string[]): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const fileInput = ref<HTMLInputElement>();
|
||||||
|
const files = ref<FileItem[]>([]);
|
||||||
|
|
||||||
|
// 初始化已有文件
|
||||||
|
watchEffect(() => {
|
||||||
|
if (props.modelValue && props.modelValue.length > 0) {
|
||||||
|
files.value = props.modelValue.map(url => ({
|
||||||
|
name: url.split("/").pop() || "file",
|
||||||
|
size: 0,
|
||||||
|
url,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleFileSelect(event: Event) {
|
||||||
|
const input = event.target as HTMLInputElement;
|
||||||
|
const selectedFiles = Array.from(input.files || []);
|
||||||
|
|
||||||
|
if (!selectedFiles.length)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 检查文件数量限制
|
||||||
|
if (files.value.length + selectedFiles.length > props.maxFiles) {
|
||||||
|
// TODO: 显示错误提示
|
||||||
|
console.warn(`最多只能上传 ${props.maxFiles} 个文件`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedFiles.forEach((file) => {
|
||||||
|
// 检查文件大小
|
||||||
|
if (file.size > props.maxSize * 1024 * 1024) {
|
||||||
|
console.warn(`文件 ${file.name} 超过 ${props.maxSize}MB 限制`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建预览 URL
|
||||||
|
const url = URL.createObjectURL(file);
|
||||||
|
files.value.push({
|
||||||
|
name: file.name,
|
||||||
|
size: file.size,
|
||||||
|
url,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更新值
|
||||||
|
updateValue();
|
||||||
|
|
||||||
|
// 重置 input
|
||||||
|
if (fileInput.value) {
|
||||||
|
fileInput.value.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFile(index: number) {
|
||||||
|
const file = files.value[index];
|
||||||
|
if (file.url && file.url.startsWith("blob:")) {
|
||||||
|
URL.revokeObjectURL(file.url);
|
||||||
|
}
|
||||||
|
files.value.splice(index, 1);
|
||||||
|
updateValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateValue() {
|
||||||
|
const urls = files.value.map(f => f.url || "").filter(Boolean);
|
||||||
|
emit("update:modelValue", urls);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatFileSize(bytes: number): string {
|
||||||
|
if (bytes === 0)
|
||||||
|
return "0 B";
|
||||||
|
const k = 1024;
|
||||||
|
const sizes = ["B", "KB", "MB", "GB"];
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
return `${Number.parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function triggerFileInput() {
|
||||||
|
fileInput.value?.click();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="file-upload">
|
||||||
|
<div v-if="label" class="file-upload-label">
|
||||||
|
{{ label }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input
|
||||||
|
ref="fileInput"
|
||||||
|
type="file"
|
||||||
|
:accept="accept"
|
||||||
|
:multiple="multiple"
|
||||||
|
class="file-input-hidden"
|
||||||
|
@change="handleFileSelect"
|
||||||
|
>
|
||||||
|
|
||||||
|
<!-- 上传按钮 -->
|
||||||
|
<ion-button
|
||||||
|
v-if="files.length < maxFiles"
|
||||||
|
expand="block"
|
||||||
|
fill="outline"
|
||||||
|
class="upload-button"
|
||||||
|
@click="triggerFileInput"
|
||||||
|
>
|
||||||
|
<ion-icon slot="start" :icon="documentAttachOutline" />
|
||||||
|
{{ placeholder || t('common.uploadFile') }}
|
||||||
|
</ion-button>
|
||||||
|
|
||||||
|
<!-- 文件列表 -->
|
||||||
|
<div v-if="files.length > 0" class="file-list">
|
||||||
|
<div v-for="(file, index) in files" :key="index" class="file-item">
|
||||||
|
<div class="file-info">
|
||||||
|
<ion-icon :icon="documentAttachOutline" class="file-icon" />
|
||||||
|
<div class="file-details">
|
||||||
|
<div class="file-name">
|
||||||
|
{{ file.name }}
|
||||||
|
</div>
|
||||||
|
<div v-if="file.size" class="file-size">
|
||||||
|
{{ formatFileSize(file.size) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ion-button fill="clear" size="small" color="danger" @click="removeFile(index)">
|
||||||
|
<ion-icon slot="icon-only" :icon="trashOutline" />
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="files.length > 0" class="file-count">
|
||||||
|
{{ files.length }} / {{ maxFiles }} {{ t('common.files') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.file-upload {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-upload-label {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: var(--ion-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-input-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-button {
|
||||||
|
--border-style: dashed;
|
||||||
|
--border-width: 2px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 12px;
|
||||||
|
background: var(--ion-color-light);
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-item:hover {
|
||||||
|
background: var(--ion-color-light-shade);
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
color: var(--ion-color-primary);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-details {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--ion-text-color);
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-size {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--ion-color-medium);
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-count {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--ion-color-medium);
|
||||||
|
text-align: right;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
41
src/components/ui/textarea-label/index.vue
Normal file
41
src/components/ui/textarea-label/index.vue
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<script lang='ts' setup>
|
||||||
|
import type { ComponentInstance } from "vue";
|
||||||
|
import { IonTextarea } from "@ionic/vue";
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
label?: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const vm = getCurrentInstance()!;
|
||||||
|
|
||||||
|
function changeRef(exposed: any) {
|
||||||
|
vm.exposed = exposed;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({} as ComponentInstance<typeof UiInput>);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div v-if="label" class="label">
|
||||||
|
{{ label }}
|
||||||
|
</div>
|
||||||
|
<component :is="h(IonTextarea, { ...$attrs, ref: changeRef })" class="ui-textarea" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.label {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
color: var(--ion-text-color-secondary);
|
||||||
|
}
|
||||||
|
.ui-textarea {
|
||||||
|
--padding-start: 12px;
|
||||||
|
--padding-end: 12px;
|
||||||
|
--background: var(--ui-input-background, #fff);
|
||||||
|
--color: var(--ui-input-color, #000);
|
||||||
|
--border-radius: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -146,8 +146,7 @@
|
|||||||
"productValue": "تقييم المنتج",
|
"productValue": "تقييم المنتج",
|
||||||
"enterProductValue": "الرجاء إدخال تقييم المنتج (بالدولار الأمريكي)",
|
"enterProductValue": "الرجاء إدخال تقييم المنتج (بالدولار الأمريكي)",
|
||||||
"assetProof": "إثبات الأصول",
|
"assetProof": "إثبات الأصول",
|
||||||
"enterAssetProof": "الرجاء إدخال إثبات الأصول",
|
"enterAssetProof": "الرجاء إدخال إثبات الأصول", "uploadAssetProof": "تحميل مستندات إثبات الأصول", "totalSupplyLimit": "الحد الأقصى لإجمالي الإصدار",
|
||||||
"totalSupplyLimit": "الحد الأقصى لإجمالي الإصدار",
|
|
||||||
"enterTotalSupplyLimit": "الرجاء إدخال الحد الأقصى لإجمالي الإصدار",
|
"enterTotalSupplyLimit": "الرجاء إدخال الحد الأقصى لإجمالي الإصدار",
|
||||||
"editionName": "اسم فترة الإصدار",
|
"editionName": "اسم فترة الإصدار",
|
||||||
"enterEditionName": "الرجاء إدخال اسم فترة الإصدار",
|
"enterEditionName": "الرجاء إدخال اسم فترة الإصدار",
|
||||||
@@ -163,6 +162,8 @@
|
|||||||
"enterUnitPrice": "الرجاء إدخال سعر الوحدة",
|
"enterUnitPrice": "الرجاء إدخال سعر الوحدة",
|
||||||
"dividendRate": "معدل الأرباح",
|
"dividendRate": "معدل الأرباح",
|
||||||
"enterDividendRate": "معدل الأرباح (مثل 0.01 يمثل 1٪)",
|
"enterDividendRate": "معدل الأرباح (مثل 0.01 يمثل 1٪)",
|
||||||
|
"description": "وصف المنتج",
|
||||||
|
"enterDescription": "الرجاء إدخال وصف المنتج",
|
||||||
"issuePeriodIndex": "فترة الإصدار {index}",
|
"issuePeriodIndex": "فترة الإصدار {index}",
|
||||||
"realEstate": "العقارات",
|
"realEstate": "العقارات",
|
||||||
"snickers": "الحلوى",
|
"snickers": "الحلوى",
|
||||||
@@ -274,10 +275,12 @@
|
|||||||
"chat": "الدردشة",
|
"chat": "الدردشة",
|
||||||
"user": "حسابي"
|
"user": "حسابي"
|
||||||
},
|
},
|
||||||
"auth": {
|
|
||||||
"common": {
|
"common": {
|
||||||
"failedSendCode": "فشل إرسال رمز التحقق."
|
"failedSendCode": "فشل إرسال رمز التحقق",
|
||||||
|
"uploadFile": "تحميل ملف",
|
||||||
|
"files": "ملفات"
|
||||||
},
|
},
|
||||||
|
"auth": {
|
||||||
"login": {
|
"login": {
|
||||||
"title": "تسجيل الدخول",
|
"title": "تسجيل الدخول",
|
||||||
"loginButton": "تسجيل الدخول",
|
"loginButton": "تسجيل الدخول",
|
||||||
|
|||||||
@@ -147,6 +147,7 @@
|
|||||||
"enterProductValue": "Please enter product valuation (USD)",
|
"enterProductValue": "Please enter product valuation (USD)",
|
||||||
"assetProof": "Asset Proof",
|
"assetProof": "Asset Proof",
|
||||||
"enterAssetProof": "Please enter asset proof",
|
"enterAssetProof": "Please enter asset proof",
|
||||||
|
"uploadAssetProof": "Upload Asset Proof Documents",
|
||||||
"totalSupplyLimit": "Total Supply Limit",
|
"totalSupplyLimit": "Total Supply Limit",
|
||||||
"enterTotalSupplyLimit": "Please enter total supply limit",
|
"enterTotalSupplyLimit": "Please enter total supply limit",
|
||||||
"editionName": "Edition Name",
|
"editionName": "Edition Name",
|
||||||
@@ -163,6 +164,8 @@
|
|||||||
"enterUnitPrice": "Please enter unit price",
|
"enterUnitPrice": "Please enter unit price",
|
||||||
"dividendRate": "Dividend Rate",
|
"dividendRate": "Dividend Rate",
|
||||||
"enterDividendRate": "Dividend rate (e.g., 0.01 for 1%)",
|
"enterDividendRate": "Dividend rate (e.g., 0.01 for 1%)",
|
||||||
|
"description": "Product Description",
|
||||||
|
"enterDescription": "Please enter product description",
|
||||||
"issuePeriodIndex": "Issue Period {index}",
|
"issuePeriodIndex": "Issue Period {index}",
|
||||||
"realEstate": "Real Estate",
|
"realEstate": "Real Estate",
|
||||||
"snickers": "Snickers",
|
"snickers": "Snickers",
|
||||||
@@ -274,10 +277,12 @@
|
|||||||
"chat": "Chat",
|
"chat": "Chat",
|
||||||
"user": "Profile"
|
"user": "Profile"
|
||||||
},
|
},
|
||||||
"auth": {
|
|
||||||
"common": {
|
"common": {
|
||||||
"failedSendCode": "Failed to send verification code"
|
"failedSendCode": "Failed to send verification code",
|
||||||
|
"uploadFile": "Upload File",
|
||||||
|
"files": "files"
|
||||||
},
|
},
|
||||||
|
"auth": {
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Log in",
|
"title": "Log in",
|
||||||
"loginButton": "Log in",
|
"loginButton": "Log in",
|
||||||
|
|||||||
@@ -147,6 +147,7 @@
|
|||||||
"enterProductValue": "请输入产品估值(美元)",
|
"enterProductValue": "请输入产品估值(美元)",
|
||||||
"assetProof": "资产证明",
|
"assetProof": "资产证明",
|
||||||
"enterAssetProof": "请输入资产证明",
|
"enterAssetProof": "请输入资产证明",
|
||||||
|
"uploadAssetProof": "上传资产证明文件",
|
||||||
"totalSupplyLimit": "总发行量上限",
|
"totalSupplyLimit": "总发行量上限",
|
||||||
"enterTotalSupplyLimit": "请输入总发行量上限",
|
"enterTotalSupplyLimit": "请输入总发行量上限",
|
||||||
"editionName": "发行期名称",
|
"editionName": "发行期名称",
|
||||||
@@ -163,6 +164,8 @@
|
|||||||
"enterUnitPrice": "请输入单价",
|
"enterUnitPrice": "请输入单价",
|
||||||
"dividendRate": "分红率",
|
"dividendRate": "分红率",
|
||||||
"enterDividendRate": "分红率(如0.01代表1%)",
|
"enterDividendRate": "分红率(如0.01代表1%)",
|
||||||
|
"description": "产品描述",
|
||||||
|
"enterDescription": "请输入产品描述",
|
||||||
"issuePeriodIndex": "发行期 {index}",
|
"issuePeriodIndex": "发行期 {index}",
|
||||||
"realEstate": "房地产",
|
"realEstate": "房地产",
|
||||||
"snickers": "糖果",
|
"snickers": "糖果",
|
||||||
@@ -274,10 +277,12 @@
|
|||||||
"chat": "聊天",
|
"chat": "聊天",
|
||||||
"user": "我的"
|
"user": "我的"
|
||||||
},
|
},
|
||||||
"auth": {
|
|
||||||
"common": {
|
"common": {
|
||||||
"failedSendCode": "发送验证码失败"
|
"failedSendCode": "发送验证码失败",
|
||||||
|
"uploadFile": "上传文件",
|
||||||
|
"files": "个文件"
|
||||||
},
|
},
|
||||||
|
"auth": {
|
||||||
"login": {
|
"login": {
|
||||||
"title": "登录",
|
"title": "登录",
|
||||||
"loginButton": "登录",
|
"loginButton": "登录",
|
||||||
|
|||||||
@@ -147,6 +147,7 @@
|
|||||||
"enterProductValue": "請輸入產品估值(美元)",
|
"enterProductValue": "請輸入產品估值(美元)",
|
||||||
"assetProof": "資產證明",
|
"assetProof": "資產證明",
|
||||||
"enterAssetProof": "請輸入資產證明",
|
"enterAssetProof": "請輸入資產證明",
|
||||||
|
"uploadAssetProof": "上傳資產證明文件",
|
||||||
"totalSupplyLimit": "總發行量上限",
|
"totalSupplyLimit": "總發行量上限",
|
||||||
"enterTotalSupplyLimit": "請輸入總發行量上限",
|
"enterTotalSupplyLimit": "請輸入總發行量上限",
|
||||||
"editionName": "發行期名稱",
|
"editionName": "發行期名稱",
|
||||||
@@ -163,6 +164,8 @@
|
|||||||
"enterUnitPrice": "請輸入單價",
|
"enterUnitPrice": "請輸入單價",
|
||||||
"dividendRate": "分紅率",
|
"dividendRate": "分紅率",
|
||||||
"enterDividendRate": "分紅率(如0.01代表1%)",
|
"enterDividendRate": "分紅率(如0.01代表1%)",
|
||||||
|
"description": "產品描述",
|
||||||
|
"enterDescription": "請輸入產品描述",
|
||||||
"issuePeriodIndex": "發行期 {index}",
|
"issuePeriodIndex": "發行期 {index}",
|
||||||
"realEstate": "房地產",
|
"realEstate": "房地產",
|
||||||
"snickers": "糖果",
|
"snickers": "糖果",
|
||||||
@@ -274,10 +277,12 @@
|
|||||||
"chat": "聊天",
|
"chat": "聊天",
|
||||||
"user": "我的"
|
"user": "我的"
|
||||||
},
|
},
|
||||||
"auth": {
|
|
||||||
"common": {
|
"common": {
|
||||||
"failedSendCode": "發送驗證碼失敗"
|
"failedSendCode": "發送驗證碼失敗",
|
||||||
|
"uploadFile": "上傳文件",
|
||||||
|
"files": "個文件"
|
||||||
},
|
},
|
||||||
|
"auth": {
|
||||||
"login": {
|
"login": {
|
||||||
"title": "登錄",
|
"title": "登錄",
|
||||||
"loginButton": "登錄",
|
"loginButton": "登錄",
|
||||||
|
|||||||
@@ -95,19 +95,6 @@ function handleSubmit(values: GenericObject) {
|
|||||||
<ErrorMessage name="estimatedValue" />
|
<ErrorMessage name="estimatedValue" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
<Field name="proofDocuments" type="text">
|
|
||||||
<template #default="{ field }">
|
|
||||||
<ui-input-label
|
|
||||||
v-bind="field"
|
|
||||||
:label="t('asset.issue.apply.assetProof')"
|
|
||||||
:placeholder="t('asset.issue.apply.enterAssetProof')"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</Field>
|
|
||||||
<ErrorMessage name="proofDocuments" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Field name="totalSupplyLimit" type="text">
|
<Field name="totalSupplyLimit" type="text">
|
||||||
<template #default="{ field }">
|
<template #default="{ field }">
|
||||||
@@ -122,6 +109,35 @@ function handleSubmit(values: GenericObject) {
|
|||||||
<ErrorMessage name="totalSupplyLimit" />
|
<ErrorMessage name="totalSupplyLimit" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Field name="description" type="text">
|
||||||
|
<template #default="{ field }">
|
||||||
|
<ui-textarea-label
|
||||||
|
v-bind="field"
|
||||||
|
:label="t('asset.issue.apply.description')"
|
||||||
|
:placeholder="t('asset.issue.apply.enterDescription')"
|
||||||
|
:maxlength="500"
|
||||||
|
:auto-grow="true"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</Field>
|
||||||
|
<ErrorMessage name="description" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Field v-slot="{ field }" name="proofDocuments">
|
||||||
|
<ui-file-upload
|
||||||
|
v-bind="field"
|
||||||
|
:label="t('asset.issue.apply.assetProof')"
|
||||||
|
:placeholder="t('asset.issue.apply.uploadAssetProof')"
|
||||||
|
:max-files="5"
|
||||||
|
:max-size="10"
|
||||||
|
accept="application/pdf,image/*,.doc,.docx"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
<ErrorMessage name="proofDocuments" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<ion-button type="submit" expand="block" shape="round" color="success">
|
<ion-button type="submit" expand="block" shape="round" color="success">
|
||||||
{{ t('asset.issue.apply.next') }}
|
{{ t('asset.issue.apply.next') }}
|
||||||
</ion-button>
|
</ion-button>
|
||||||
@@ -129,4 +145,12 @@ function handleSubmit(values: GenericObject) {
|
|||||||
</Form>
|
</Form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='css' scoped></style>
|
<style lang='css' scoped>
|
||||||
|
ion-textarea {
|
||||||
|
--padding-start: 12px;
|
||||||
|
--padding-end: 12px;
|
||||||
|
--background: var(--ui-input-background, #fff);
|
||||||
|
--color: var(--ui-input-color, #000);
|
||||||
|
--border-radius: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user