优化资产编辑表单,移除第三方资产和无库存限制选项,新增配送方式选项,优化图片URL处理逻辑

This commit is contained in:
WUSIJIAN
2025-12-22 17:57:15 +08:00
parent 4fedcd16df
commit 7b8e9f40cc

View File

@@ -19,14 +19,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="第三方资产">
<el-switch v-model="ruleForm.sourceType" inline-prompt active-text="是" inactive-text="否" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="8">
<el-form-item label="资产分类" prop="categoryId"> <el-form-item label="资产分类" prop="categoryId">
<el-cascader <el-cascader
v-model="ruleForm.categoryId" v-model="ruleForm.categoryId"
@@ -35,10 +28,14 @@
placeholder="请选择资产分类" placeholder="请选择资产分类"
clearable clearable
class="w100" class="w100"
:disabled="isEdit"
@change="onCategoryChange" @change="onCategoryChange"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="上线时间"> <el-form-item label="上线时间">
<el-date-picker <el-date-picker
@@ -188,71 +185,15 @@
<template v-if="ruleForm.type === 'physical'"> <template v-if="ruleForm.type === 'physical'">
<el-divider content-position="left">实物资产配置</el-divider> <el-divider content-position="left">实物资产配置</el-divider>
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="8">
<el-form-item label="无库存限制">
<el-switch v-model="ruleForm.physicalAssetConfig.unlimitedStock" inline-prompt active-text="是" inactive-text="否" />
</el-form-item>
</el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="配送方式"> <el-form-item label="配送方式">
<el-select v-model="ruleForm.physicalAssetConfig.shipping.deliveryMethod" placeholder="请选择配送方式" class="w100"> <el-select v-model="ruleForm.physicalAssetConfig.shipping.deliveryMethod" placeholder="请选择配送方式" class="w100">
<el-option label="快递" value="express" /> <el-option label="快递" value="express" />
<el-option label="自提" value="self_pickup" /> <el-option label="自提" value="self_pickup" />
<el-option label="同城配送" value="city_delivery" disabled />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8" v-if="ruleForm.physicalAssetConfig.shipping.deliveryMethod === 'express'">
<el-form-item label="发货周期">
<el-input-number v-model="ruleForm.physicalAssetConfig.shipping.deliveryTime" :min="1" :max="720" class="w100" />
<span class="unit-text">小时</span>
</el-form-item>
</el-col>
</el-row>
</template>
<!-- 虚拟资产配置 -->
<template v-if="ruleForm.type === 'virtual'">
<el-divider content-position="left">虚拟资产配置</el-divider>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="HTTP方法">
<el-select v-model="ruleForm.virtualAssetConfig.method" placeholder="请选择HTTP方法" class="w100">
<el-option label="GET" value="GET" />
<el-option label="POST" value="POST" />
<el-option label="PUT" value="PUT" />
<el-option label="DELETE" value="DELETE" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="请求地址">
<el-input v-model="ruleForm.virtualAssetConfig.requestURL" placeholder="请输入请求地址" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="认证类型">
<el-select v-model="ruleForm.virtualAssetConfig.authType" placeholder="请选择认证类型" class="w100">
<el-option label="无认证" value="none" />
<el-option label="API Key" value="apikey" />
<el-option label="Bearer Token" value="bearer" />
<el-option label="OAuth" value="oauth" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24" v-if="ruleForm.virtualAssetConfig.authType && ruleForm.virtualAssetConfig.authType !== 'none'">
<el-col :span="24">
<el-form-item label="认证配置">
<el-input
v-model="ruleForm.virtualAssetConfig.authConfig"
type="textarea"
:rows="4"
placeholder='请输入认证配置JSON例如{"api_key": "your_api_key"}'
/>
</el-form-item>
</el-col>
</el-row> </el-row>
</template> </template>
@@ -280,12 +221,6 @@
<span class="unit-text">分钟</span> <span class="unit-text">分钟</span>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6">
<el-form-item label="最大用户">
<el-input-number v-model="ruleForm.serviceAssetConfig.capacity.maxUsers" :min="0" class="w100" />
<span class="unit-text">0=无限</span>
</el-form-item>
</el-col>
</el-row> </el-row>
<!-- 时间段配置 --> <!-- 时间段配置 -->
@@ -301,7 +236,15 @@
<el-input-number v-model="slot.capacity" :min="1" placeholder="容量" style="width: 100px" controls-position="right" /> <el-input-number v-model="slot.capacity" :min="1" placeholder="容量" style="width: 100px" controls-position="right" />
<el-button type="danger" :icon="Delete" circle size="small" @click="removeTimeSlot(index)" /> <el-button type="danger" :icon="Delete" circle size="small" @click="removeTimeSlot(index)" />
</div> </div>
<el-button type="primary" :icon="Plus" size="small" @click="addTimeSlot">添加时间段</el-button> <el-button
type="primary"
:icon="Plus"
size="small"
@click="addTimeSlot"
:disabled="isTimeSlotLimitReached"
>
添加时间段
</el-button>
</div> </div>
</el-form-item> </el-form-item>
@@ -351,8 +294,9 @@ export default {
</script> </script>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, watch } from 'vue'; import { ref, reactive, watch, computed } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import type { FormInstance, FormRules } from 'element-plus';
import { Plus, Delete } from '@element-plus/icons-vue'; import { Plus, Delete } from '@element-plus/icons-vue';
import { getAsset, createAsset, updateAsset } from '/@/api/assets/asset'; import { getAsset, createAsset, updateAsset } from '/@/api/assets/asset';
import { getCategoryTree, getCategory } from '/@/api/assets/category'; import { getCategoryTree, getCategory } from '/@/api/assets/category';
@@ -385,14 +329,12 @@ interface CategoryAttr {
interface RuleForm { interface RuleForm {
id: string; id: string;
name: string; name: string;
sourceType: boolean;
type: string; type: string;
categoryId: string; categoryId: string;
description: string; description: string;
onlineTime: string; onlineTime: string;
offlineTime: string; offlineTime: string;
physicalAssetConfig: { physicalAssetConfig: {
unlimitedStock: boolean;
shipping: { shipping: {
deliveryMethod: string; deliveryMethod: string;
deliveryTime: number; deliveryTime: number;
@@ -423,13 +365,16 @@ interface RuleForm {
const emit = defineEmits(['getAssetList']); const emit = defineEmits(['getAssetList']);
const formRef = ref(); const formRef = ref<FormInstance>();
const editAssetRef = ref();
const MAX_TIME_SLOTS = 7;
const isShowDialog = ref(false); const isShowDialog = ref(false);
const isEdit = ref(false); const isEdit = ref(false);
const submitLoading = ref(false); const submitLoading = ref(false);
const formLoading = ref(false); const formLoading = ref(false);
const categoryOptions = ref<any[]>([]); const categoryOptions = ref<any[]>([]);
const categoryAttrs = ref<CategoryAttr[]>([]); const categoryAttrs = ref<CategoryAttr[]>([]);
const isTimeSlotLimitReached = computed(() => ruleForm.serviceAssetConfig.schedule.timeSlots.length >= MAX_TIME_SLOTS);
// 获取属性的key // 获取属性的key
const getAttrKey = (attr: CategoryAttr): string => { const getAttrKey = (attr: CategoryAttr): string => {
@@ -447,19 +392,38 @@ const mainImagePreview = ref('');
const imageFileList = ref<UploadUserFile[]>([]); const imageFileList = ref<UploadUserFile[]>([]);
const dialogVisible = ref(false); const dialogVisible = ref(false);
const dialogImageUrl = ref(''); const dialogImageUrl = ref('');
// 图片拼接
const imgAddressPrefix = ref('');
const formatImageUrl = (url?: string) => {
if (!url) return '';
if (/^https?:\/\//i.test(url)) return url;
return `${imgAddressPrefix.value || ''}${url}`;
};
const createDefaultTimeSlots = (): TimeSlot[] => {
const slots: TimeSlot[] = [];
for (let i = 1; i <= MAX_TIME_SLOTS; i++) {
slots.push({
dayOfWeek: String(i),
startTime: '09:00',
endTime: '18:00',
capacity: 100,
});
}
return slots;
};
// 初始表单数据 // 初始表单数据
const getInitialForm = (): RuleForm => ({ const getInitialForm = (): RuleForm => ({
id: '', id: '',
name: '', name: '',
sourceType: false,
type: 'physical', type: 'physical',
categoryId: '', categoryId: '',
description: '', description: '',
onlineTime: '', onlineTime: '',
offlineTime: '', offlineTime: '',
physicalAssetConfig: { physicalAssetConfig: {
unlimitedStock: false,
shipping: { shipping: {
deliveryMethod: 'express', deliveryMethod: 'express',
deliveryTime: 24, deliveryTime: 24,
@@ -473,7 +437,7 @@ const getInitialForm = (): RuleForm => ({
}, },
serviceAssetConfig: { serviceAssetConfig: {
schedule: { schedule: {
timeSlots: [], timeSlots: createDefaultTimeSlots(),
exceptions: [], exceptions: [],
}, },
booking: { booking: {
@@ -490,10 +454,19 @@ const getInitialForm = (): RuleForm => ({
const ruleForm = reactive<RuleForm>(getInitialForm()); const ruleForm = reactive<RuleForm>(getInitialForm());
const rules = { const validateOfflineTime = (_rule: any, value: string, callback: Function) => {
if (value && ruleForm.onlineTime && new Date(value).getTime() < new Date(ruleForm.onlineTime).getTime()) {
callback(new Error('下线时间不能早于上线时间'));
} else {
callback();
}
};
const rules: FormRules = {
name: [{ required: true, message: '资产名称不能为空', trigger: 'blur' }], name: [{ required: true, message: '资产名称不能为空', trigger: 'blur' }],
type: [{ required: true, message: '请选择资产类型', trigger: 'change' }], type: [{ required: true, message: '请选择资产类型', trigger: 'change' }],
categoryId: [{ required: true, message: '请选择资产分类', trigger: 'change' }], categoryId: [{ required: true, message: '请选择资产分类', trigger: 'change' }],
offlineTime: [{ validator: validateOfflineTime, trigger: 'change' }],
}; };
// 主图上传处理 // 主图上传处理
@@ -506,6 +479,8 @@ const handleMainImageChange = (file: UploadFile) => {
// 图片列表预览 // 图片列表预览
const handlePictureCardPreview = (file: UploadFile) => { const handlePictureCardPreview = (file: UploadFile) => {
console.log(file,'111');
dialogImageUrl.value = file.url || ''; dialogImageUrl.value = file.url || '';
dialogVisible.value = true; dialogVisible.value = true;
}; };
@@ -564,6 +539,7 @@ const resetForm = () => {
mainImagePreview.value = ''; mainImagePreview.value = '';
imageFileList.value = []; imageFileList.value = [];
categoryAttrs.value = []; categoryAttrs.value = [];
imgAddressPrefix.value = '';
}; };
// 获取分类数据 // 获取分类数据
@@ -608,9 +584,9 @@ const openDialog = (row?: any, edit?: boolean) => {
getAsset(row.id) getAsset(row.id)
.then((res: any) => { .then((res: any) => {
const data = res.data; const data = res.data;
imgAddressPrefix.value = data.imgAddressPrefix || '';
ruleForm.id = data.id || ''; ruleForm.id = data.id || '';
ruleForm.name = data.name || ''; ruleForm.name = data.name || '';
ruleForm.sourceType = data.sourceType || false;
ruleForm.type = data.type || 'physical'; ruleForm.type = data.type || 'physical';
ruleForm.categoryId = data.categoryId || ''; ruleForm.categoryId = data.categoryId || '';
ruleForm.description = data.description || ''; ruleForm.description = data.description || '';
@@ -619,14 +595,14 @@ const openDialog = (row?: any, edit?: boolean) => {
// 主图预览 // 主图预览
if (data.imageUrl) { if (data.imageUrl) {
mainImagePreview.value = data.imageUrl; mainImagePreview.value = formatImageUrl(data.imageUrl);
} }
// 图片列表 // 图片列表
if (data.images && Array.isArray(data.images)) { if (data.images && Array.isArray(data.images)) {
imageFileList.value = data.images.map((url: string, index: number) => ({ imageFileList.value = data.images.map((url: string, index: number) => ({
name: `image-${index}`, name: `image-${index}`,
url: url, url: formatImageUrl(url),
})); }));
} }
@@ -687,7 +663,6 @@ const buildFormData = (): FormData => {
formData.append('id', ruleForm.id); formData.append('id', ruleForm.id);
} }
formData.append('name', ruleForm.name); formData.append('name', ruleForm.name);
formData.append('sourceType', String(ruleForm.sourceType));
formData.append('type', ruleForm.type); formData.append('type', ruleForm.type);
formData.append('categoryId', ruleForm.categoryId); formData.append('categoryId', ruleForm.categoryId);
formData.append('description', ruleForm.description || ''); formData.append('description', ruleForm.description || '');
@@ -729,7 +704,9 @@ const buildFormData = (): FormData => {
// 提交 // 提交
const onSubmit = () => { const onSubmit = () => {
formRef.value.validate((valid: boolean) => { const form = formRef.value;
if (!form) return;
form.validate((valid: boolean) => {
if (valid) { if (valid) {
submitLoading.value = true; submitLoading.value = true;
const formData = buildFormData(); const formData = buildFormData();