refactor: 优化上传表单组件和类型定义

This commit is contained in:
wangqiao
2025-09-06 18:39:16 +08:00
parent 24d2b82221
commit b7d6b37e87
6 changed files with 92 additions and 102 deletions

View File

@ -16,7 +16,7 @@ export const create = (params: TcreateReq) => {
* @returns * @returns
*/ */
export const parent = (params: { type: string | number; parentId: number | string }) => { export const parent = (params: { type: string | number; parentId: number | string }) => {
return useFetchRequest.get<IResponse<parentRes[]>>('/prod-api/app-api/business/app/dict/parent', { query: params }) return useDollarFetchRequest.get<IResponse<parentRes[]>>('/prod-api/app-api/business/app/dict/parent', { query: params })
} }
/** /**
* 获取具有上下级的字典信息 * 获取具有上下级的字典信息
@ -32,7 +32,7 @@ export const parentV2 = (params: { type: string | number; parentId: number | str
* @returns * @returns
*/ */
export const indexTabs = () => { export const indexTabs = () => {
return useFetchRequest.get<IResponse<parentRes[]>>('/prod-api/app-api/business/project/index/index-tab3') return useDollarFetchRequest.get<IResponse<parentRes[]>>('/prod-api/app-api/business/project/index/index-tab3')
} }
/** /**
* 模糊查询获取标签内容 * 模糊查询获取标签内容

View File

@ -10,9 +10,9 @@ export interface FileItem {
// 定义整个 JSON 对象的类型 // 定义整个 JSON 对象的类型
export interface TcreateReq { export interface TcreateReq {
activeName: string activeName: string | number
id: number | string id: number | string
type: any[] type: number
isDomestic: number | string isDomestic: number | string
province: string // 省份编码 province: string // 省份编码
city: string // 城市编码 city: string // 城市编码

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<el-form-item label-width="110px" :prop="`${props.vaildRules}.files`" :rules="{ required: true, message: '请上传图纸', trigger: ['blur', 'change'] }"> <!-- <el-form-item label-width="110px" :prop="`${props.vaildRules}.files`" :rules="{ required: true, message: '请上传图纸', trigger: ['blur', 'change'] }">
<KlUploader <KlUploader
v-model:file-list="form.files" v-model:file-list="form.files"
:limit="1000" :limit="1000"
@ -11,33 +11,44 @@
@preview="handlePreview" @preview="handlePreview"
> >
</KlUploader> </KlUploader>
</el-form-item> </el-form-item> -->
<el-form-item <el-form-item
label-width="110px" label-width="110px"
label="标题:" label="标题:"
:prop="`${props.vaildRules}.title`" :prop="`${props.vaildRules}.title`"
:rules="{ required: true, message: '请输入标题', trigger: ['blur', 'change'] }" :rules="[
{ required: true, message: '20-50 字符,结构可用分类关键词+作品名/资源价值版本/使用场景', trigger: ['blur', 'change'] },
{
validator: (rule: any, value: any, callback: any) => {
if (value && value.length < 20) {
callback(new Error('20-50 字符,结构可用分类关键词+作品名/资源价值版本/使用场景'))
}
callback()
},
trigger: ['blur', 'change'],
},
]"
> >
<el-input v-model="form.title" placeholder="请输入标题" class="w-361px!" maxlength="128"></el-input> <el-input v-model="form.title" placeholder="请输入标题" minlength="20" maxlength="50"></el-input>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
label-width="110px" label-width="110px"
label="分类:" label="专业分类:"
:prop="`${props.vaildRules}.projectType`" :prop="`${props.vaildRules}.projectType`"
:rules="{ required: true, message: '请选择分类', trigger: ['blur', 'change'] }" :rules="{ required: true, message: '请选择分类', trigger: ['blur', 'change'] }"
> >
<!-- <el-select v-model="form.projectType" placeholder="请选择分类" class="w-361px!" multiple> <!-- <el-select v-model="form.projectType" placeholder="请选择分类" class="w-361px!" multiple>
<el-option v-for="(item, index) in projectTypeList" :key="index" :label="item.name" :value="item.id" /> <el-option v-for="(item, index) in projectTypeList" :key="index" :label="item.name" :value="item.id" />
</el-select> --> </el-select> -->
<el-cascader v-model="form.projectType" class="w-361px!" :options="projectTypeList" :props="cascaderProps" clearable collapse-tags /> <el-cascader v-model="form.projectType" class="w-[100%]!" :options="projectTypeList" :props="cascaderProps" clearable collapse-tags />
</el-form-item> </el-form-item>
<el-form-item <el-form-item
label-width="110px" label-width="110px"
label="软件版本" label="软件分类"
:prop="`${props.vaildRules}.editions`" :prop="`${props.vaildRules}.editions`"
:rules="{ required: true, message: '请选择软件版本', trigger: ['blur', 'change'] }" :rules="{ required: true, message: '请选择软件版本', trigger: ['blur', 'change'] }"
> >
<el-select v-model="form.editions" placeholder="请选择软件版本" class="w-361px!"> <el-select v-model="form.editions" placeholder="请选择软件版本">
<el-option v-for="(item, index) in editionsList" :key="index" :label="item.name" :value="item.id" /> <el-option v-for="(item, index) in editionsList" :key="index" :label="item.name" :value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -54,20 +65,11 @@
</el-form-item> </el-form-item>
<el-form-item <el-form-item
label-width="110px" label-width="110px"
label="标签:" label="作品标签:"
:prop="`${props.vaildRules}.labels`" :prop="`${props.vaildRules}.labels`"
:rules="{ required: true, message: '请选择标签', trigger: ['blur', 'change'] }" :rules="{ required: false, message: '请选择标签', trigger: ['blur', 'change'] }"
> >
<el-select <el-select v-model="form.labels" :remote-method="remoteMethod" :loading="loading" multiple filterable remote placeholder="请输入搜索标签">
v-model="form.labels"
:remote-method="remoteMethod"
:loading="loading"
multiple
filterable
remote
placeholder="请输入搜索标签"
class="w-361px!"
>
<el-option v-for="(item, index) in labelsList" :key="index" :label="item" :value="item" /> <el-option v-for="(item, index) in labelsList" :key="index" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -75,11 +77,11 @@
label-width="110px" label-width="110px"
label="金币:" label="金币:"
:prop="`${props.vaildRules}.points`" :prop="`${props.vaildRules}.points`"
:rules="{ required: true, message: '请输入金币', trigger: ['blur', 'change'] }" :rules="{ required: true, message: '金币设置分销为0-15,设置0金币为专属资源可直接获利2-15金币', trigger: ['blur', 'change'] }"
> >
<el-input-number v-model="form.points" :controls="false" :precision="0" :min="0" placeholder="请输入金币" class="w-361px! text-left!"></el-input-number> <el-input-number v-model="form.points" :controls="false" :precision="0" :min="0" placeholder="请输入金币" class="w-[100%]! text-left!"></el-input-number>
</el-form-item> </el-form-item>
<el-form-item <!-- <el-form-item
label-width="110px" label-width="110px"
label="图形格式:" label="图形格式:"
:prop="`${props.vaildRules}.formatType`" :prop="`${props.vaildRules}.formatType`"
@ -88,7 +90,7 @@
<el-checkbox-group v-model="form.formatType"> <el-checkbox-group v-model="form.formatType">
<el-checkbox v-for="(item, index) in formatTypeList" :key="index" :label="item" :value="item"></el-checkbox> <el-checkbox v-for="(item, index) in formatTypeList" :key="index" :label="item" :value="item"></el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item> -->
<el-form-item <el-form-item
label-width="110px" label-width="110px"
label="上传封面:" label="上传封面:"
@ -103,9 +105,9 @@
tips="上传图片支持jpg/gif/png格式、第一张为封面图片、每张图片大小不得超过1M" tips="上传图片支持jpg/gif/png格式、第一张为封面图片、每张图片大小不得超过1M"
@validate="formRef?.validateField(`${props.vaildRules}.coverImages`)" @validate="formRef?.validateField(`${props.vaildRules}.coverImages`)"
> >
<div class="h-77px w-161px flex items-center justify-center border border-[#cdd0d6] rounded-1px border-dashed bg-[#fafafa]"> <div class="h-[77px] w-[161px] flex items-center justify-center border border-[#cdd0d6] rounded-[1px] border-dashed bg-[#fafafa]">
<el-icon class="text-[#999999]"><Plus /></el-icon> <el-icon class="text-[#999999]"><Plus /></el-icon>
<div class="ml-4px mt-2px text-14px text-[#999999] font-normal">上传图纸</div> <div class="ml-[4px] mt-[2px] text-[14px] text-[#999999] font-normal">上传图纸</div>
</div> </div>
</KlUploader> </KlUploader>
</el-form-item> </el-form-item>
@ -123,9 +125,9 @@
:show-tip="false" :show-tip="false"
@validate="formRef?.validateField(`${props.vaildRules}.renderings`)" @validate="formRef?.validateField(`${props.vaildRules}.renderings`)"
> >
<div class="h-77px w-161px flex items-center justify-center border border-[#cdd0d6] rounded-1px border-dashed bg-[#fafafa]"> <div class="h-[77px] w-[161px] flex items-center justify-center border border-[#cdd0d6] rounded-[1px] border-dashed bg-[#fafafa]">
<el-icon class="text-[#999999]"><Plus /></el-icon> <el-icon class="text-[#999999]"><Plus /></el-icon>
<div class="ml-4px mt-2px text-14px text-[#999999] font-normal">上传图纸</div> <div class="ml-[4px] mt-[2px] text-[14px] text-[#999999] font-normal">上传图纸</div>
</div> </div>
</KlUploader> </KlUploader>
</el-form-item> </el-form-item>
@ -134,15 +136,15 @@
</el-form-item> </el-form-item>
<el-form-item <el-form-item
label-width="110px" label-width="110px"
label="描述:" label="作品描述:"
:prop="`${props.vaildRules}.description`" :prop="`${props.vaildRules}.description`"
:rules="[ :rules="[
{ required: true, message: '请输入描述', trigger: ['blur', 'change'] }, { required: true, message: '简介字数限制60-150 字符,需包含用途、文件介绍、适用场景等', trigger: ['blur', 'change'] },
{ {
validator: (rule, value, callback) => { validator: (rule, value, callback) => {
console.log(rule) console.log(rule)
if (value.length < 70) { if (value.length < 60) {
callback(new Error('输入内容不能少于 70 字')) callback(new Error('简介字数限制60-150 字符,需包含用途、文件介绍、适用场景等'))
} else { } else {
callback() callback()
} }
@ -151,7 +153,7 @@
}, },
]" ]"
> >
<el-input v-model="form.description" type="textarea" :rows="6" placeholder="请输入描述" class="w-361px!" minlength="70" show-word-limit></el-input> <el-input v-model="form.description" type="textarea" :rows="6" placeholder="请输入描述" minlength="60" maxlength="150" show-word-limit></el-input>
</el-form-item> </el-form-item>
</div> </div>
</template> </template>
@ -216,7 +218,7 @@
formatTypeList.value = res.data formatTypeList.value = res.data
}) })
} }
getFormatTypeList() // getFormatTypeList()
const projectTypeList = ref<any>([]) const projectTypeList = ref<any>([])
/** 获取分类下拉框 */ /** 获取分类下拉框 */
@ -225,7 +227,6 @@
projectTypeList.value = res.data projectTypeList.value = res.data
}) })
} }
getParent()
/** 版本 */ /** 版本 */
const editionsList = ref<any>([]) const editionsList = ref<any>([])
@ -237,11 +238,15 @@
editionsList.value = res.data editionsList.value = res.data
}) })
} }
getEditionsList()
const handlePreview = (val: any) => { const handlePreview = (val: any) => {
emit('preview', val) emit('preview', val)
} }
onMounted(() => {
getEditionsList()
getParent()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="box-border border border-[#EEEEEE] rounded-12px border-solid bg-[#FFFFFF] px-33px py-22px pb-10px!"> <div class="box-border border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] px-[33px] py-[22px] pb-[10px]!">
<el-form-item <el-form-item
label="选择上传资料类型:" label="选择上传资料类型:"
label-width="170px" label-width="170px"
@ -7,37 +7,40 @@
prop="type" prop="type"
:rules="[{ required: true, message: '请选择上传资料类型', trigger: 'change' }]" :rules="[{ required: true, message: '请选择上传资料类型', trigger: 'change' }]"
> >
<el-checkbox-group v-model="form.type" @change="handleTypeChange"> <el-radio-group v-model="form.type" @change="handleTypeChange(form.type)">
<el-checkbox :value="1">图纸</el-checkbox> <el-radio :value="1">图纸</el-radio>
<el-checkbox :value="3">模型</el-checkbox> <el-radio :value="3">模型</el-radio>
<el-checkbox :value="2">文本</el-checkbox> <el-radio :value="2">文本</el-radio>
</el-checkbox-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item <div class="flex gap-[20px]">
label="选择国家:"
label-width="110px"
label-position="left"
prop="isDomestic"
:rules="[{ required: true, message: '请选择国家', trigger: 'change' }]"
>
<el-select v-model="form.isDomestic" placeholder="请选择" class="w-200px!" @change="handleCountryChange">
<el-option label="国内" :value="1"></el-option>
<el-option label="国外" :value="0"></el-option>
</el-select>
</el-form-item>
<div class="flex">
<el-form-item <el-form-item
label="选择国家:"
label-width="110px"
label-position="left"
prop="isDomestic"
:rules="[{ required: true, message: '请选择国家', trigger: 'change' }]"
>
<el-select v-model="form.isDomestic" placeholder="请选择" class="w-[200px]!" @change="handleCountryChange">
<el-option label="国内" :value="1"></el-option>
<el-option label="国外" :value="0"></el-option>
</el-select>
</el-form-item>
<el-form-item
v-if="form.isDomestic === 0"
label="所在地区:" label="所在地区:"
label-width="110px" label-width="110px"
label-position="left" label-position="left"
prop="province" prop="province"
:rules="[{ required: true, message: '请选择所在地区', trigger: 'change' }]" :rules="[{ required: true, message: '请选择所在地区', trigger: 'change' }]"
> >
<el-select v-model="form.province" placeholder="请选择" class="w-200px!" @change="handleProvinceChange"> <el-select v-model="form.province" filterable placeholder="请选择" class="w-[200px]!">
<el-option v-for="(item, index) in provinceList" :key="index" :label="item.name" :value="item.id" /> <el-option v-for="(item, index) in provinceList" :key="index" :label="item.name" :value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label-width="10px" label-position="left" prop="city" :rules="[{ required: true, message: '请选择地址', trigger: 'change' }]"> </div>
<!-- <div class="flex"> -->
<!-- <el-form-item label-width="10px" label-position="left" prop="city" :rules="[{ required: true, message: '请选择地址', trigger: 'change' }]">
<el-select v-model="form.city" placeholder="请选择" class="w-200px!" @change="handleCityChange"> <el-select v-model="form.city" placeholder="请选择" class="w-200px!" @change="handleCityChange">
<el-option v-for="(item, index) in cityList" :key="index" :label="item.name" :value="item.id" /> <el-option v-for="(item, index) in cityList" :key="index" :label="item.name" :value="item.id" />
</el-select> </el-select>
@ -46,8 +49,8 @@
<el-select v-model="form.county" placeholder="请选择" class="w-200px!"> <el-select v-model="form.county" placeholder="请选择" class="w-200px!">
<el-option v-for="(item, index) in countyList" :key="index" :label="item.name" :value="item.id" /> <el-option v-for="(item, index) in countyList" :key="index" :label="item.name" :value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item> -->
</div> <!-- </div> -->
</div> </div>
</template> </template>
@ -63,32 +66,16 @@
// 添加旧值引用 // 添加旧值引用
const oldTypeValue = ref<(number | string)[]>([]) const oldTypeValue = ref<(number | string)[]>([])
const handleTypeChange = (val: any) => { const handleTypeChange = (val: number) => {
console.log(val, 'val') form.value.draws = [
{
// 新增的项(当前值有但旧值没有的)
const added = val.filter((item: number | string) => !oldTypeValue.value.includes(item))
// 减少的项(旧值有但当前值没有的)
const removed = oldTypeValue.value.filter((item) => !val.includes(item))
if (added.length) {
form.value.draws.push({
...JSON.parse(JSON.stringify(DrawsEnmu)), ...JSON.parse(JSON.stringify(DrawsEnmu)),
type: added[0], type: val,
}) },
} else if (removed.length) { ]
form.value.draws = form.value.draws.filter((item) => item.type !== removed[0])
}
// 更新旧值
oldTypeValue.value = [...val]
// 更新当前activeName值
if (!val?.length) {
form.value.activeName = ''
}
nextTick(() => { nextTick(() => {
form.value.activeName = val[val.length - 1] form.value.activeName = val
}) })
} }

View File

@ -1,20 +1,18 @@
<template> <template>
<div class="ml-[23px] box-border min-h-[930px] w-[516px] border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] px-[33px] py-[22px]"> <div class="ml-[23px] box-border min-h-[930px] w-[516px] border border-[#EEEEEE] rounded-[12px] border-solid bg-[#FFFFFF] px-[33px] py-[22px]">
<div class="flex items-center"> <!-- <div class="flex items-center">
<img src="~/assets/images/preview.png" alt="" srcset="" width="16px" height="19px" /><span class="ml-[7px] text-[18px] text-[#333333] font-normal" <img src="~/assets/images/preview.png" alt="" srcset="" width="16px" height="19px" /><span class="ml-[7px] text-[18px] text-[#333333] font-normal">
>预览</span 预览
></div </span>
> </div> -->
<div class="mt-[20px]"> <!-- <div class="mt-[20px]">
<el-image :src="previewUrl" class="mb-[16px] max-h-[320px] max-w-[460px] min-h-[200px]" fit="contain"></el-image> <el-image :src="previewUrl" class="mb-[16px] max-h-[320px] max-w-[460px] min-h-[200px]" fit="contain"></el-image>
<span class="text-[16px] text-[#333333] font-normal">{{ previewName || '图纸标题' }}</span></div <span class="text-[16px] text-[#333333] font-normal">{{ previewName || '图纸标题' }}</span></div
> > -->
<div class="my-[30px] h-[1px] w-[460px] rounded-[1px] bg-[#EEEEEE]"></div> <!-- <div class="my-[30px] h-[1px] w-[460px] rounded-[1px] bg-[#EEEEEE]"></div> -->
<div class="flex items-center"> <div class="flex items-center">
<img src="~/assets/images/tip.png" width="20px" height="20px" /> <img src="~/assets/images/tip.png" width="20px" height="20px" />
<span class="ml-[7px] text-[18px] text-[#333333] font-normal"> <span class="ml-[7px] text-[18px] text-[#333333] font-normal"> 上传遇到问题可以咨询 </span>
上传遇到问题可以咨询
</span>
</div> </div>
<div class="mt-[20px] text-center"><el-image src="https://picsum.photos/290/290?_t" alt="" srcset="" class="h-[290px] w-[290px]" /></div> <div class="mt-[20px] text-center"><el-image src="https://picsum.photos/290/290?_t" alt="" srcset="" class="h-[290px] w-[290px]" /></div>
<div class="mt-[30px] text-center text-[16px] text-[#333333] font-normal"> <div class="mt-[30px] text-center text-[16px] text-[#333333] font-normal">

View File

@ -36,9 +36,9 @@
const router = useRouter() // 导入路由实例,用于跳转页面 const router = useRouter() // 导入路由实例,用于跳转页面
const form = reactive<TcreateReq>({ const form = reactive<TcreateReq>({
activeName: '', // 标签 activeName: 1, // 标签
id: '', // 图纸id id,示例值(24548) id: '', // 图纸id id,示例值(24548)
type: [], // 图纸类型 类型,示例值(1) type: 1, // 图纸类型 类型,示例值(1)
isDomestic: '', // 是否是国内: 1是 0否 isDomestic: '', // 是否是国内: 1是 0否
province: '', // 省份编码 province: '', // 省份编码
city: '', // 城市编码 city: '', // 城市编码
@ -121,12 +121,12 @@
} }
// 图纸类型 // 图纸类型
const drawTypeRef = ref() const drawTypeRef = ref<InstanceType<typeof DrawType>>()
onMounted(() => { onMounted(() => {
// 初始化图纸类型 // 初始化图纸类型
drawTypeRef.value.handleTypeChange([1]) drawTypeRef.value?.handleTypeChange(1)
// 初始化图纸类型 // 初始化图纸类型
form.type = [1] form.type = 1
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>