123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659 |
- <template>
- <!-- div 包裹突出 -->
- <el-collapse v-model="activeNames" class="bg-content">
- <template v-for="(dialogArray, i) in editCollapseArray">
- <el-collapse-item
- :name="i + 1 + ''"
- v-if="!dialogArray.hide"
- :disabled="dialogArray.disabled"
- >
- <template #title>
- <div class="t-title">
- {{ dialogArray.label }}
- </div>
- </template>
- <div class="bg-dialog">
- <div
- v-for="(item, index) in dialogArray.children"
- :style="`width: ${item.form?.width ? item.form.width : '100%'}`"
- :key="index"
- >
- <div
- v-if="item.form?.type === 'title' && !item.form?.slotSetEdit"
- style="
- padding: 20px 0;
- margin-left: 8%;
- display: flex;
- flex-direction: row;
- "
- class="as-gravity-center"
- >
- <div style="background-color: #999; height: 1px; flex: 1"></div>
- <el-text class="as-bold" size="large" style="padding: 0 20px">
- {{ item.label }}
- </el-text>
- <div style="background-color: #999; height: 1px; flex: 1"></div>
- </div>
- <!-- 此处的width决定了是否要换行 v-show="!item.form.hide"-->
- {{ form[item.form.prop ? item.form.prop : item.prop] }}
- <el-form-item
- style="position: relative"
- v-if="
- !item.form?.hideEdit &&
- !item.form?.hide &&
- item.form?.type != 'title'
- "
- class="as-bold"
- :label="item.label"
- :prop="item.prop"
- :label-width="
- item.form?.formLabelWidth
- ? item.form.formLabelWidth
- : formLabelWidth
- "
- :error="item.form?.error"
- :rules="rules[item.prop]"
- >
- <!-- 输入框 -->
- <div style="width: 100%" v-if="item.form.type === 'input'">
- <!-- :readonly="true" 只读 -->
- <el-input
- v-trim
- clearable
- :disabled="item.form.disabled"
- v-model="form[item.prop]"
- :type="item.form.itemType"
- :min="item.form.min"
- :max="item.form.max"
- :placeholder="item.form.placeholder"
- :rows="item.form.rows"
- @change="
- customSelectorSelection(
- $event,
- item.form.prop ? item.form.prop : item.prop,
- form,
- item,
- dialogArray.children
- )
- "
- :maxlength="item.form.maxlength ?? 60"
- @input="
- handleBeforeInput($event, item.form.checkContent, item)
- "
- >
- <!-- 输入框单位 -->
- <template v-if="item.unit" #append>
- <el-button
- @click="unitClick($event, item, form[item.prop])"
- >
- {{ item.unit }}
- </el-button>
- </template>
- </el-input>
- </div>
- <!-- 区间输入框 -->
- <div style="width: 100%" v-if="item.form.type === 'section'">
- <div class="num-input">
- <el-input
- v-trim
- clearable
- :disabled="item.form.disabled"
- v-model="form[item.props].split(',')[0]"
- :type="item.form.itemType"
- :placeholder="item.form.placeholder"
- :rows="item.form.rows"
- :maxlength="item.form.maxlength ?? 60"
- >
- <!-- 输入框单位 -->
- <template v-if="item.unit" #append>
- {{ item.unit }}
- </template>
- </el-input>
- <span>-</span>
- <el-input
- v-trim
- clearable
- :disabled="item.form.disabled"
- v-model="form[item.props].split(',')[1]"
- :type="item.form.itemType"
- :placeholder="item.form.placeholder"
- :rows="item.form.rows"
- :maxlength="item.form.maxlength ?? 60"
- >
- <!-- 输入框单位 -->
- <template v-if="item.unit" #append>
- {{ item.unit }}
- </template>
- </el-input>
- </div>
- </div>
- <!-- 级联选择 -->
- <div style="width: 100%" v-if="item.form.type === 'cascader'">
- <el-cascader
- style="width: 100%"
- clearable
- v-model="form[item.prop]"
- :disabled="item.form.disabled"
- :placeholder="item.form.placeholder"
- :options="item.form.options"
- :props="{ multiple: item.form.multiple }"
- :collapse-tags="item.form.collapseTags"
- :collapse-tags-tooltip="item.form.collapseTags"
- />
- </div>
- <!-- 单选框 -->
- <div style="width: 100%" v-if="item.form.type === 'radio'">
- <el-radio-group v-model="form[item.prop]" class="ml-4">
- <el-radio
- v-for="(itemData, index) in item.form.listData"
- :key="index"
- :label="itemData.value"
- >
- {{ itemData.label }}
- </el-radio>
- </el-radio-group>
- </div>
-
- <!-- 选择框 -->
- <div style="width: 100%" v-else-if="item.form.type === 'select'">
- <!-- {{ form[item.form.prop ? item.form.prop : item.prop] }} -->
- <el-select
- filterable
- clearable
- style="width: 100%"
- value-key="lable"
- v-model="form[item.form.prop ? item.form.prop : item.prop]"
- @change="
- customSelectorSelection(
- $event,
- item.form.prop ? item.form.prop : item.prop,
- form,
- item,
- dialogArray.children
- )
- "
- :disabled="item.form.disabled"
- :placeholder="item.form.placeholder"
- :multiple="item.form.multiple"
- >
- <el-option
- v-for="(itemData, index) in item.form.listData"
- :key="index"
- :label="itemData.label"
- :value="itemData.value"
- />
- </el-select>
- </div>
- <!-- 异步选择框 -->
- <div
- style="width: 100%"
- v-else-if="item.form.type === 'lazySelect'"
- >
- <lazy-select
- @lazySelectorSelection="lazySelectorSelection"
- :item="item"
- :form="form"
- :disabled="item.form.disabled"
- :prop="item.form.prop ? item.form.prop : item.prop"
- :api="item.form.api"
- :returnSuffixName="item.form.returnSuffixName"
- :parameter="item.form.parameter"
- :name="item.form.name"
- :id="item.form.id"
- :multiple="item.form.multiple"
- ></lazy-select>
- </div>
- <!-- 日期框 -->
- <div style="width: 100%" v-else-if="item.form.type === 'date'">
- <el-date-picker
- unlink-panels
- @change="
- customSelectorSelection(
- $event,
- item.form.prop ? item.form.prop : item.prop,
- form,
- item,
- dialogArray.children
- )
- "
- style="width: 100%"
- v-model="form[item.prop]"
- :disabled="item.form.disabled"
- :format="form.format"
- :value-format="item.form.valueFormat || form.valueFormat"
- :type="item.form.itemType"
- :placeholder="item.form.placeholder"
- />
- </div>
- <!-- 图片文件 -->
- <div
- style="width: 100%"
- v-else-if="item.form.type === 'uploadImg'"
- >
- <el-upload
- ref="uploadImg"
- class="avatar-uploader"
- :style="
- (item.form.width
- ? 'width: ' + item.form.width + 'px;'
- : '') +
- (item.form.height
- ? 'height:' + item.form.height + 'px'
- : '')
- "
- :limit="1"
- :on-exceed="handleImg"
- :data="data"
- accept=".png,.jpg,jpeg"
- :before-upload="beforeAvatarImgUpload"
- :show-file-list="false"
- :action="uploadUrl"
- @success="onSuccess($event, item)"
- >
- <img
- v-if="form[item.prop]"
- :src="changeAddress(form[item.prop])"
- class="avatar"
- :style="
- (item.form.width
- ? 'width: ' + item.form.width + 'px;'
- : '') +
- (item.form.height
- ? 'height:' + item.form.height + 'px'
- : '')
- "
- />
- <el-icon
- v-else
- class="avatar-uploader-icon"
- :style="
- (item.form.width
- ? 'width: ' + item.form.width + 'px;'
- : '') +
- (item.form.height
- ? 'height:' + item.form.height + 'px'
- : '')
- "
- >
- <Plus />
- </el-icon>
- <template #tip>
- <div class="el-upload__tip">
- {{ item.form.placeholder }}
- </div>
- </template>
- </el-upload>
- </div>
- <!-- 文件上传 drag(是否拖拽上传) multiple(是否支持多文件) action(请求URL) auto-upload(是否自动上传文件)-->
- <div style="width: 100%" v-else-if="item.form.type === 'upload'">
- <el-upload
- ref="upload"
- class="upload-demo"
- :file-list="fileList"
- drag
- :limit="item.form.limit || 1"
- :on-exceed="(files) => handleExceed(files, item.form.limit)"
- :before-upload="
- (el) =>
- beforeAvatarUpload(
- el,
- item.form.suffixType,
- item.form.typeHint
- )
- "
- :data="data"
- :action="uploadUrl"
- :on-remove="(el) => onRemove(el, item)"
- @success="onSuccess($event, item)"
- :accept="item.form.accept"
- >
- <el-icon class="el-icon--upload">
- <UploadFilled />
- </el-icon>
- <!-- <el-icon class="el-icon--upload"><el-image :src="Android" /></el-icon> -->
- <div class="el-upload__text">
- 在此提交文件或
- <em>点击上传</em>
- </div>
- <template #tip>
- <div class="el-upload__tip">
- <!-- 提示内容 -->
- {{ item.form.placeholder }}
- </div>
- </template>
- </el-upload>
- </div>
- <!-- 提示 -->
- <el-popover
- v-if="item.form.isPopover"
- placement="top-start"
- title="提示"
- :width="200"
- trigger="hover"
- :content="item.form.popoverContent"
- >
- <template #reference>
- <QuestionFilled
- style="
- width: 20px;
- height: 20px;
- color: #dc362e;
- position: absolute;
- right: -30px;
- z-index: 2;
- "
- />
- </template>
- </el-popover>
- <!-- 自定义插槽 -->
- <div
- v-else-if="!item.form.type && item.form.slotSetEdit"
- style="width: 100%"
- >
- <slot :name="item.form.slotSetNameEdit" />
- </div>
- </el-form-item>
- </div>
- </div>
- </el-collapse-item>
- </template>
- </el-collapse>
- </template>
- <script setup lang="ts">
- import { onMounted, ref, watch, nextTick } from 'vue'
- import { genFileId, ElMessage } from 'element-plus'
- import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus'
- import Android from '@/assets/image/android.png' //默认头像资源
- // @ts-ignore lazySelect模板
- import lazySelect from '@/components/lazySelect/lazySelect.vue'
- import { changeAddress } from '@/utils/utils'
- import { rule } from 'postcss'
-
- const props = defineProps({
- form: {
- //表单数据内容
- type: Object,
- default: function () {
- return {}
- },
- required: true,
- },
- editCollapseArray: {
- //表单展示内容数据 tableFrom.dialogArray
- type: Array as () => any[],
- default: () => [],
- required: true,
- },
- formLabelWidth: {
- //表单宽度
- type: String,
- default: '80px',
- },
- dialogFormVisible: {
- type: Boolean,
- },
- rules: {
- type: Object,
- default: function () {
- return {}
- },
- },
- defaultActiveNames: {
- type: Array as () => any[],
- default: function () {
- return []
- },
- },
- })
- const activeNames = ref(props.defaultActiveNames)
- const uploadUrl = '/minIo/upload'
- const data = { bucket: '' }
- const upload = ref<UploadInstance>()
- const uploadImg = ref<UploadInstance>()
- const emit = defineEmits([
- 'customSelectorSelection',
- 'handleBeforeInput',
- 'lazySelectorSelection',
- 'unitClick',
- 'uploadSuccess',
- ])
-
- //选择组件变化监听
- function customSelectorSelection(value, title, form, item, dialogArray) {
- console.log('选择内容', value, title)
- emit('customSelectorSelection', value, title, form, item, dialogArray)
- }
-
- //文件上传成功
- const fileList = ref<any>([])
- function onSuccess(response: any, item: any) {
- // import.meta.env.VITE_APP_UPLOAD_URL +
- const url = response.data.ossFilePath
- fileList.value.push(url)
- props.form[item.prop] = fileList.value.join(';')
- console.log(props.form[item.prop], fileList.value)
- emit('uploadSuccess', response, item)
- }
- function onRemove(response: any, item: any) {
- const index = fileList.value.indexOf(
- response.response.data.ossFilePath
- )
- if (index !== -1) {
- fileList.value.splice(index, 1)
- }
- console.log(index)
- props.form[item.prop] = fileList.value.join(';')
- console.log(fileList.value, response, props.form[item.prop])
- }
- //单位点击事件
- function unitClick($event, item, value) {
- emit('unitClick', $event, item, value)
- }
-
- //覆盖替换上一个文件
- const handleImg: UploadProps['onExceed'] = (files) => {
- uploadImg.value![0].clearFiles()
- const file = files[0] as UploadRawFile
- file.uid = genFileId()
- uploadImg.value![0].handleStart(file)
- uploadImg.value![0].submit()
- }
-
- //覆盖替换上一个文件
- const handleExceed: UploadProps['onExceed'] = (files, limit) => {
- console.log(files, limit)
- if (limit) {
- return ElMessage.error(`限制最多上传${limit}个文件`)
- } else {
- fileList.value.splice(0, 1)
- upload.value![0].clearFiles()
- const file = files[0] as UploadRawFile
- file.uid = genFileId()
- upload.value![0].handleStart(file)
- nextTick(() => {
- upload.value![0].submit()
- })
- }
- }
-
- const beforeAvatarImgUpload: UploadProps['beforeUpload'] = (rawFile) => {
- if (rawFile.size / 1024 / 1024 > 5) {
- ElMessage.error('文件大小不能超过 5MB!')
- return false
- }
- return true
- }
-
- // 清除文件
- watch(
- () => props.dialogFormVisible,
- (newValue) => {
- if (newValue) {
- fileList.value = []
- if (upload.value && upload.value![0]) upload.value![0].clearFiles()
- }
- }
- )
- watch(
- () => props.form,
- (newValue) => {
- if (newValue) {
- console.log(newValue, 'newValue')
- }
- },
- {
- deep: true,
- }
- )
-
- //限制上传文件 application/vnd.android.package-archive(应用) image/jpeg(图片文件)
- const beforeAvatarUpload: any = (rawFile, suffixType, typeHint) => {
- if (suffixType && rawFile) {
- const suffix = rawFile.name?.slice(
- rawFile.name?.indexOf('.') + 1,
- rawFile.name?.length
- )
- if (suffixType.indexOf(suffix) == -1) {
- ElMessage.error(typeHint ?? '请上传正确文件格式')
- return false
- } else {
- return true
- }
- } else {
- return true
- }
- // if (rawFile.type !== 'application/vnd.android.package-archive') {
- // ElMessage.error('请上传正确的应用文件')
- // return false
- // } else if (rawFile.size / 1024 / 1024 > 200) {
- // ElMessage.error('文件大小不能超过 200MB!')
- // return false
- // }
- }
-
- //APP版本号校验
- function handleBeforeInput(value, checkContent, item) {
- if (checkContent) {
- if (checkContent == 'version') {
- //限制输入版本号
- // 匹配形如 x.y.z 的版本号
- const regex = /[^\d\.]/g
- if (!regex.test(value)) {
- item.form.error = ''
- } else {
- props.form[item.prop] = ''
- item.form.error = '版本号格式不正确,请输入形如 x.y.z 的版本号'
- }
- } else if (checkContent == 'money') {
- //金额校验
- const regex = /^\d*(\.\d{0,2})?$/
- if (regex.test(value)) {
- item.form.error = ''
- props.form[item.prop] = value.trim()
- } else {
- props.form[item.prop] = ''
- item.form.error = '请输入正确的数据格式'
- }
- //限制输入金额
- if (value.length > 15) {
- props.form[item.prop] = value.slice(0, 15)
- item.form.error = '最多只能输入15位'
- }
- } else if (checkContent == 'percentage') {
- //限制输入金额
- //金额校验
- const regex = /^\d*(\.\d{0,2})?$/
- if (regex.test(value) && value <= 100) {
- item.form.error = ''
- props.form[item.prop] = value.trim()
- } else {
- props.form[item.prop] = ''
- item.form.error = '请输入正确的数据格式且最大值为100'
- }
- } else if (checkContent == 'integer') {
- //数字校验
- const regex = /^[0-9]\d*$/
- if (regex.test(value)) {
- item.form.error = ''
- props.form[item.prop] = value.trim()
- } else {
- props.form[item.prop] = ''
- item.form.error = '只能输入整数'
- if(item.form.min === 3){
- item.form.error = '产品编号最少输入三位'
- }
- }
- if (
- item?.form?.integerlength &&
- value.toString().length > item.form.integerlength
- ) {
- props.form[item.prop] = value.slice(0, item.form.integerlength)
- item.form.error = `最多只能输入${item.form.integerlength}位`
- }
- if (
- item?.form?.min &&
- value.toString().length < item.form.min
- ) {
- // props.form[item.prop] = value.slice(0, item.form.min)
- item.form.error = `最少输入${item.form.min}位`
- }
- }
- } else {
- item.form.error = ''
- }
- if (item?.form?.digit && value.length > item.form.digit) {
- props.form[item.prop] = value.slice(0, item.form.digit)
- item.form.error = `最多只能输入${item.form.digit}位`
- }
-
- emit('handleBeforeInput', value, item, props.form)
- }
-
- function lazySelectorSelection(value, title, form) {
- emit('lazySelectorSelection', value, title, form)
- }
- </script>
- <style lang="scss" scoped>
- .bg-content {
- width: 100%;
- }
- .t-title {
- font-size: 20px;
- }
- .avatar-uploader .avatar {
- width: 375px;
- height: 280px;
- display: block;
- }
-
- .avatar-uploader .el-upload {
- border: 1px dashed var(--el-border-color);
- border-radius: 6px;
- cursor: pointer;
- position: relative;
- overflow: hidden;
- transition: var(--el-transition-duration-fast);
- }
-
- .avatar-uploader .el-upload:hover {
- border-color: var(--el-color-primary);
- }
-
- .el-icon.avatar-uploader-icon {
- font-size: 28px;
- color: #8c939d;
- border: 1px dashed #8c939d;
- border-radius: 6px;
- width: 375px;
- height: 280px;
- text-align: center;
- }
-
- ::v-deep .el-form-item__content {
- flex-wrap: nowrap;
- }
-
- :deep(.el-input-number .el-input__inner) {
- text-align: left;
- }
- </style>
|