yumi-admin/apps/src/views/operate/system-country.vue

415 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { Page } from '@vben/common-ui';
import {
OSS_FILE_BUCKETS,
getAccessImgUrl,
simpleUploadFile,
} from '#/api/legacy/oss';
import {
addSysCountryCode,
pageSysCountryCode,
updateSysCountryCode,
} from '#/api/legacy/system';
import { formatDate } from '#/views/system/shared';
import {
Button,
Card,
Form,
FormItem,
Image,
Input,
Modal,
Pagination,
Switch,
Table,
Tag,
message,
} from 'antdv-next';
defineOptions({ name: 'OperateSystemCountry' });
const loading = ref(false);
const total = ref(0);
const list = ref<Array<Record<string, any>>>([]);
const formOpen = ref(false);
const submitLoading = ref(false);
const uploadLoading = ref(false);
const fileInputRef = ref<HTMLInputElement | null>(null);
const formMode = ref<'create' | 'edit'>('edit');
const query = reactive<Record<string, any>>({
aliasName: '',
countryName: '',
cursor: 1,
limit: 30,
});
const form = reactive<Record<string, any>>({
aliasName: '',
alphaThree: '',
alphaTwo: '',
countryName: '',
countryNumeric: '',
countryCodeAliasesInput: '',
id: '',
nationalFlag: '',
open: false,
phonePrefix: '',
sort: '',
top: 0,
});
const columns: any[] = [
{ dataIndex: 'countryName', key: 'countryName', title: '国家名称', width: 200 },
{ dataIndex: 'alphaTwo', key: 'alphaTwo', title: '二字码', width: 100 },
{ dataIndex: 'alphaThree', key: 'alphaThree', title: '三字码', width: 100 },
{ dataIndex: 'aliasName', key: 'aliasName', title: '别名', width: 160 },
{ dataIndex: 'countryCodeAliases', key: 'countryCodeAliases', title: '国家码集合', width: 220 },
{ dataIndex: 'nationalFlag', key: 'nationalFlag', title: '国旗', width: 120 },
{ dataIndex: 'open', key: 'open', title: '开放状态', width: 120 },
{ dataIndex: 'phonePrefix', key: 'phonePrefix', title: '手机号码前缀', width: 140 },
{ dataIndex: 'sort', key: 'sort', title: '排序', width: 100 },
{ dataIndex: 'createTime', key: 'createTime', title: '创建时间', width: 180 },
{ dataIndex: 'actions', key: 'actions', title: '操作', width: 220 },
];
async function loadData(reset = false) {
if (reset) {
query.cursor = 1;
}
loading.value = true;
try {
const result = await pageSysCountryCode({ ...query });
list.value = result.records || [];
total.value = result.total || 0;
} finally {
loading.value = false;
}
}
function handleSearch() {
void loadData(true);
}
function handlePageChange(page: number, pageSize: number) {
query.cursor = page;
query.limit = pageSize;
void loadData();
}
function openEdit(record: Record<string, any>) {
formMode.value = 'edit';
form.aliasName = record.aliasName || '';
form.alphaThree = record.alphaThree || '';
form.alphaTwo = record.alphaTwo || '';
form.countryName = record.countryName || '';
form.countryNumeric = record.countryNumeric || '';
form.countryCodeAliasesInput = Array.isArray(record.countryCodeAliases)
? record.countryCodeAliases.join(',')
: '';
form.id = record.id || '';
form.nationalFlag = record.nationalFlag || '';
form.open = record.open ?? false;
form.phonePrefix = record.phonePrefix || '';
form.sort = record.sort || '';
form.top = record.top === true || record.top === 1;
formOpen.value = true;
}
function resetForm() {
form.aliasName = '';
form.alphaThree = '';
form.alphaTwo = '';
form.countryName = '';
form.countryNumeric = '';
form.countryCodeAliasesInput = '';
form.id = '';
form.nationalFlag = '';
form.open = false;
form.phonePrefix = '';
form.sort = '';
form.top = false;
}
function openCreate() {
resetForm();
formMode.value = 'create';
formOpen.value = true;
}
function pickFlag() {
fileInputRef.value?.click();
}
async function uploadFlag(event: Event) {
const file = (event.target as HTMLInputElement).files?.[0];
if (!file) {
return;
}
uploadLoading.value = true;
try {
const result = await simpleUploadFile(file, OSS_FILE_BUCKETS.other);
form.nationalFlag = getAccessImgUrl(result.name);
} finally {
uploadLoading.value = false;
(event.target as HTMLInputElement).value = '';
}
}
async function saveForm() {
if (!form.nationalFlag) {
message.warning('请上传国旗');
return;
}
if (!String(form.alphaTwo || '').trim()) {
message.warning('请填写国家二字码');
return;
}
if (!String(form.alphaThree || '').trim()) {
message.warning('请填写国家三字码');
return;
}
if (!String(form.countryName || '').trim()) {
message.warning('请填写国家名称');
return;
}
if (!String(form.phonePrefix || '').trim()) {
message.warning('请填写手机号前缀');
return;
}
if (!String(form.sort || '').trim()) {
message.warning('请填写权重序号');
return;
}
submitLoading.value = true;
try {
const payload: Record<string, any> = {
...form,
alphaThree: String(form.alphaThree || '').trim().toUpperCase(),
alphaTwo: String(form.alphaTwo || '').trim().toUpperCase(),
countryNumeric: form.countryNumeric === '' ? undefined : Number(form.countryNumeric),
countryCodeAliases: String(form.countryCodeAliasesInput || '')
.split(',')
.map((item) => item.trim().toUpperCase())
.filter(Boolean),
open: form.open === true,
phonePrefix: Number(form.phonePrefix),
sort: Number(form.sort),
top: form.top === true,
};
delete payload.countryCodeAliasesInput;
if (formMode.value === 'create') {
delete payload.id;
await addSysCountryCode(payload);
} else {
await updateSysCountryCode(payload);
}
message.success('保存成功');
formOpen.value = false;
resetForm();
await loadData();
} finally {
submitLoading.value = false;
}
}
async function updateCountryState(data: Record<string, any>) {
await updateSysCountryCode(data);
message.success('操作成功');
await loadData();
}
loadData(true);
</script>
<template>
<Page title="国家管理">
<Card>
<div class="toolbar">
<Input
v-model:value="query.countryName"
allow-clear
placeholder="英文国家名称"
style="width: 220px"
/>
<Input
v-model:value="query.aliasName"
allow-clear
placeholder="别名"
style="width: 220px"
/>
<Button :loading="loading" type="primary" @click="handleSearch">搜索</Button>
<Button type="primary" @click="openCreate">新增</Button>
</div>
<Table
:columns="columns"
:data-source="list"
:loading="loading"
:pagination="false"
row-key="id"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'countryName'">
<div class="name-cell">
<Tag v-if="record.top === 1" color="red">置顶</Tag>
<span>{{ record.countryName }}</span>
</div>
</template>
<template v-else-if="column.key === 'nationalFlag'">
<Image :preview="false" :src="record.nationalFlag" class="flag" />
</template>
<template v-else-if="column.key === 'countryCodeAliases'">
{{ Array.isArray(record.countryCodeAliases) ? record.countryCodeAliases.join(', ') : '-' }}
</template>
<template v-else-if="column.key === 'open'">
{{ record.open ? '已开放' : '未开放' }}
</template>
<template v-else-if="column.key === 'createTime'">
{{ formatDate(record.createTime) }}
</template>
<template v-else-if="column.key === 'actions'">
<Button size="small" type="link" @click="openEdit(record)">修改</Button>
<Button
v-if="record.top === 0"
size="small"
type="link"
@click="updateCountryState({ id: record.id, top: 1 })"
>
置顶
</Button>
<Button
v-else
size="small"
type="link"
@click="updateCountryState({ id: record.id, top: 0 })"
>
取消置顶
</Button>
<Button
v-if="record.open === false"
size="small"
type="link"
@click="updateCountryState({ id: record.id, open: true })"
>
开放国家
</Button>
<Button
v-else
size="small"
type="link"
@click="updateCountryState({ id: record.id, open: false })"
>
取消开放
</Button>
</template>
</template>
</Table>
<div v-if="total > 0" class="pager">
<Pagination
:current="query.cursor"
:page-size="query.limit"
:total="total"
show-size-changer
@change="handlePageChange"
@showSizeChange="handlePageChange"
/>
</div>
</Card>
<Modal
:confirm-loading="submitLoading"
:open="formOpen"
destroy-on-close
:title="formMode === 'create' ? '新增' : '修改'"
@cancel="formOpen = false"
@ok="saveForm"
>
<Form layout="vertical">
<FormItem label="国旗">
<div class="upload-row">
<Image v-if="form.nationalFlag" :preview="false" :src="form.nationalFlag" class="flag" />
<Button :loading="uploadLoading" @click="pickFlag">点击上传</Button>
<input
ref="fileInputRef"
accept="image/png,image/jpg,image/jpeg"
class="hidden"
type="file"
@change="uploadFlag"
>
</div>
</FormItem>
<FormItem label="国家名称">
<Input v-model:value="form.countryName" />
</FormItem>
<FormItem label="国家二字码">
<Input v-model:value="form.alphaTwo" :maxlength="2" placeholder="例如SA" />
</FormItem>
<FormItem label="国家三字码">
<Input v-model:value="form.alphaThree" :maxlength="3" placeholder="例如SAU" />
</FormItem>
<FormItem label="数字码">
<Input v-model:value="form.countryNumeric" placeholder="例如682" />
</FormItem>
<FormItem label="别名">
<Input v-model:value="form.aliasName" />
</FormItem>
<FormItem label="国家码集合">
<Input v-model:value="form.countryCodeAliasesInput" placeholder="例如SA,KSA" />
</FormItem>
<FormItem label="手机号前缀">
<Input v-model:value="form.phonePrefix" />
</FormItem>
<FormItem label="权重序号">
<Input v-model:value="form.sort" />
</FormItem>
<FormItem label="开放状态">
<Switch v-model:checked="form.open" checked-children="已开放" un-checked-children="未开放" />
</FormItem>
</Form>
</Modal>
</Page>
</template>
<style scoped>
.toolbar {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 16px;
}
.name-cell {
align-items: center;
display: flex;
gap: 8px;
}
.flag {
border-radius: 8px;
height: 30px;
width: 45px;
}
.upload-row {
align-items: center;
display: flex;
gap: 12px;
}
.hidden {
display: none;
}
.pager {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
</style>