214 lines
5.3 KiB
Vue
214 lines
5.3 KiB
Vue
<template>
|
||
<div>
|
||
<div class="flex flex-col gap-5">
|
||
<div
|
||
v-for="section in sections"
|
||
:key="section.name"
|
||
class="grid gap-4"
|
||
:class="'grid-cols-' + section.columns"
|
||
>
|
||
<div v-for="field in section.fields" :key="field.name">
|
||
<FormControl
|
||
v-model="billingInformation[field.fieldname]"
|
||
:label="field.label || field.fieldname"
|
||
:type="getInputType(field)"
|
||
:name="field.fieldname"
|
||
:options="field.options"
|
||
:disabled="props.disableForm"
|
||
:required="field.required"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<ErrorMessage class="mt-2" :message="updateBillingInformation.error" />
|
||
</div>
|
||
</template>
|
||
<script setup>
|
||
import { FormControl, ErrorMessage, createResource } from 'jingrow-ui';
|
||
import { ref, computed, inject, watch, onMounted } from 'vue';
|
||
import { toast } from 'vue-sonner';
|
||
import { DashboardError } from '../../utils/error';
|
||
import { countryNameMap, chinaStates } from '@/utils/billing';
|
||
|
||
const emit = defineEmits(['success']);
|
||
const team = inject('team');
|
||
|
||
const billingInformation = defineModel();
|
||
const props = defineProps({
|
||
disableForm: { type: Boolean, default: false },
|
||
});
|
||
|
||
// 获取团队当前国家信息
|
||
const getBillingInformation = createResource({
|
||
url: 'jcloud.api.account.get_billing_information',
|
||
onSuccess(data) {
|
||
console.log("获取到的账单信息:", data);
|
||
if (data.country) {
|
||
// 设置当前国家,确保使用后端的准确值
|
||
billingInformation.value.country = data.country;
|
||
} else {
|
||
// 只有没有国家信息时才设置默认值
|
||
billingInformation.value.country = 'China';
|
||
}
|
||
}
|
||
});
|
||
|
||
const updateBillingInformation = createResource({
|
||
url: 'jcloud.api.account.update_billing_information',
|
||
makeParams: () => {
|
||
const billingData = { ...billingInformation.value };
|
||
|
||
// 确保国家名称正确,如果用户选择了'cn'代码,需要转换为'China'
|
||
if (billingData.country === 'cn') {
|
||
billingData.country = 'China';
|
||
}
|
||
|
||
return { billing_details: billingData };
|
||
},
|
||
validate: async () => {
|
||
let error = await validate();
|
||
if (error) throw new DashboardError(error);
|
||
},
|
||
onSuccess: () => {
|
||
toast.success('账单信息已更新');
|
||
emit('success');
|
||
},
|
||
});
|
||
|
||
// 组件挂载时获取当前账单信息
|
||
onMounted(() => {
|
||
// 获取当前账单信息,包括国家
|
||
getBillingInformation.submit();
|
||
});
|
||
|
||
// 反向映射:从代码到名称
|
||
const codeToNameMap = computed(() => {
|
||
const map = {};
|
||
Object.entries(countryNameMap).forEach(([code, name]) => {
|
||
map[code] = name;
|
||
});
|
||
return map;
|
||
});
|
||
|
||
// 国家选择列表 - 包含英文代码映射到中文显示
|
||
const countryList = computed(() => {
|
||
// 由于后端限制,目前只提供中国选项
|
||
return [{ label: '中国', value: 'China' }];
|
||
|
||
// 如果未来允许其他国家,可以恢复这个:
|
||
// return Object.entries({
|
||
// 'China': '中国',
|
||
// 'United States': '美国',
|
||
// // 其他国家...
|
||
// }).map(([code, name]) => ({
|
||
// label: name,
|
||
// value: code
|
||
// }));
|
||
});
|
||
|
||
const stateOptions = computed(() => {
|
||
return chinaStates.map((state) => ({
|
||
label: state,
|
||
value: state,
|
||
}));
|
||
});
|
||
|
||
const sections = computed(() => {
|
||
return [
|
||
{
|
||
name: '国家和城市',
|
||
columns: 2,
|
||
fields: [
|
||
{
|
||
fieldtype: 'Select',
|
||
label: '国家',
|
||
fieldname: 'country',
|
||
options: countryList.value,
|
||
required: true,
|
||
disabled: true, // 禁用国家选择
|
||
},
|
||
{
|
||
fieldtype: 'Data',
|
||
label: '城市',
|
||
fieldname: 'city',
|
||
required: true,
|
||
},
|
||
],
|
||
},
|
||
{
|
||
name: '地址',
|
||
columns: 1,
|
||
fields: [
|
||
{
|
||
fieldtype: 'Data',
|
||
label: '地址',
|
||
fieldname: 'address',
|
||
required: true,
|
||
},
|
||
],
|
||
},
|
||
{
|
||
name: '州和邮政编码',
|
||
columns: 2,
|
||
fields: [
|
||
{
|
||
fieldtype:
|
||
billingInformation.value.country === 'China' ? 'Select' : 'Data',
|
||
label: '州/省/地区',
|
||
fieldname: 'state',
|
||
required: true,
|
||
options:
|
||
billingInformation.value.country === 'China'
|
||
? stateOptions.value
|
||
: null,
|
||
},
|
||
{
|
||
fieldtype: 'Data',
|
||
label: '邮政编码',
|
||
fieldname: 'postal_code',
|
||
required: true,
|
||
},
|
||
],
|
||
},
|
||
];
|
||
});
|
||
|
||
function getInputType(field) {
|
||
return {
|
||
Data: 'text',
|
||
Int: 'number',
|
||
Select: 'select',
|
||
Check: 'checkbox',
|
||
Password: 'password',
|
||
Text: 'textarea',
|
||
Date: 'date',
|
||
}[field.fieldtype || 'Data'];
|
||
}
|
||
|
||
async function validate() {
|
||
// 验证必填字段
|
||
for (let field of sections.value.flatMap((s) => s.fields)) {
|
||
if (field.required && !billingInformation.value[field.fieldname]) {
|
||
return `${field.label} 是必填项`;
|
||
}
|
||
}
|
||
return null; // 返回null表示没有错误
|
||
}
|
||
|
||
// 组件加载时设置默认国家
|
||
watch(() => team.pg?.country, (country) => {
|
||
if (country) {
|
||
const countryOption = countryList.value.find(
|
||
(c) => c.label === country || c.value === country
|
||
);
|
||
if (countryOption) {
|
||
billingInformation.value.country = countryOption.value;
|
||
}
|
||
} else {
|
||
// 如果team.pg中没有country,默认设置为中国
|
||
billingInformation.value.country = 'China';
|
||
}
|
||
}, { immediate: true });
|
||
|
||
defineExpose({ updateBillingInformation, validate });
|
||
</script> |