mirror of
https://github.com/primedigitaltech/azon_seeker.git
synced 2026-01-19 13:13:22 +08:00
149 lines
3.6 KiB
Vue
149 lines
3.6 KiB
Vue
<script setup lang="ts">
|
|
import { useFileDialog } from '@vueuse/core';
|
|
import type { FormItemRule } from 'naive-ui';
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
disabled?: boolean;
|
|
matchPattern?: RegExp;
|
|
placeholder?: string;
|
|
validateMessage?: string;
|
|
}>(),
|
|
{
|
|
disabled: false,
|
|
matchPattern: () => /^[A-Z0-9]{10}((\n|\s|,|;)[A-Z0-9]{10})*\n?$/g,
|
|
placeholder: '输入ASINs',
|
|
validateMessage: '请输入格式正确的ASIN',
|
|
},
|
|
);
|
|
|
|
const modelValue = defineModel<string>({ required: true });
|
|
|
|
const message = useMessage();
|
|
|
|
const formItemRef = useTemplateRef('detail-form-item');
|
|
const formItemRule: FormItemRule = {
|
|
required: true,
|
|
trigger: ['submit', 'blur'],
|
|
message: props.validateMessage,
|
|
validator: () => {
|
|
return props.matchPattern.exec(modelValue.value) !== null;
|
|
},
|
|
};
|
|
|
|
const fileDialog = useFileDialog({ accept: '.txt', multiple: false });
|
|
fileDialog.onChange((fileList) => {
|
|
const file = fileList?.item(0);
|
|
file && handleImportIds(file);
|
|
fileDialog.reset();
|
|
});
|
|
|
|
const handleImportIds = (file: File) => {
|
|
const reader = new FileReader();
|
|
reader.onload = (e) => {
|
|
const content = e.target?.result;
|
|
if (typeof content === 'string') {
|
|
modelValue.value = content;
|
|
}
|
|
};
|
|
reader.readAsText(file, 'utf-8');
|
|
};
|
|
|
|
const handleExportIds = () => {
|
|
const blob = new Blob([modelValue.value], { type: 'text/plain' });
|
|
const url = URL.createObjectURL(blob);
|
|
const filename = `${new Date().toISOString()}.txt`;
|
|
const link = document.createElement('a');
|
|
link.href = url;
|
|
link.download = filename;
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
URL.revokeObjectURL(url);
|
|
message.info('导出完成');
|
|
};
|
|
|
|
defineExpose({
|
|
validate: async () =>
|
|
new Promise<boolean>((resolve) => {
|
|
formItemRef.value?.validate({
|
|
trigger: 'submit',
|
|
callback: (errors) => {
|
|
if (errors) {
|
|
resolve(false);
|
|
} else {
|
|
resolve(true);
|
|
}
|
|
},
|
|
});
|
|
}),
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="ids-input">
|
|
<div class="header">
|
|
<span>
|
|
<n-button @click="fileDialog.open()" :disabled="disabled" round size="small">
|
|
<template #icon>
|
|
<n-icon>
|
|
<gg-import />
|
|
</n-icon>
|
|
</template>
|
|
导入
|
|
</n-button>
|
|
<n-button :disabled="disabled" @click="handleExportIds" round size="small">
|
|
<template #icon>
|
|
<n-icon>
|
|
<ion-arrow-up-right-box-outline />
|
|
</n-icon>
|
|
</template>
|
|
导出
|
|
</n-button>
|
|
</span>
|
|
<span>
|
|
<n-popover v-if="$slots['extra-settings']" placement="bottom-end" trigger="click">
|
|
<template #trigger>
|
|
<n-button :disabled="disabled" circle size="small">
|
|
<template #icon>
|
|
<n-icon size="18px"><solar-settings-linear /></n-icon>
|
|
</template>
|
|
</n-button>
|
|
</template>
|
|
<slot name="extra-settings" />
|
|
</n-popover>
|
|
</span>
|
|
</div>
|
|
<div style="height: 7px" />
|
|
<n-form-item ref="detail-form-item" label-placement="left" :rule="formItemRule">
|
|
<n-input
|
|
:disabled="disabled"
|
|
v-model:value="modelValue"
|
|
:placeholder="placeholder"
|
|
type="textarea"
|
|
size="large"
|
|
/>
|
|
</n-form-item>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.asin-input {
|
|
width: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.header {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
|
|
> *:first-of-type {
|
|
display: flex;
|
|
flex-direction: row;
|
|
gap: 5px;
|
|
}
|
|
}
|
|
</style>
|