|
|
<template>
|
|
|
<view class="applyform">
|
|
|
<u-form :model="submitForm" ref="submitForms" label-position="top" :label-width="140" :label-align="'left'"
|
|
|
:error-type="['message']">
|
|
|
<block v-for="(item,index) in course_forms">
|
|
|
<u-form-item :label="item.name" :prop="item.field"
|
|
|
:required="item.rule?item.rule.indexOf('required')!==-1:false">
|
|
|
<block v-if="item.edit_input==='text'">
|
|
|
<!-- <block v-if="item.field==='introduce'
|
|
|
|| item.field==='company_product' || item.field==='company_introduce'">
|
|
|
<u-input type="textarea" :placeholder="item.help?item.help:'请输入'" v-model="item.value" />
|
|
|
</block> -->
|
|
|
<u-input v-if="item.field==='company_name'"
|
|
|
@click="showCompanySelector = true" type="select" v-model="item.value" border :placeholder="item.help?item.help:'请选择公司名称'" />
|
|
|
|
|
|
<u-input v-else :type="item.field==='introduce'||
|
|
|
item.field==='company_fund'|| item.field==='company_product'||
|
|
|
item.field==='company_introduce'?'textarea':'text'" maxlength="9999" :placeholder="item.help?item.help:'请输入'" v-model="item.value" />
|
|
|
</block>
|
|
|
<block v-if="item.edit_input==='textarea'">
|
|
|
<!-- <block v-if="item.field==='introduce'
|
|
|
|| item.field==='company_product' || item.field==='company_introduce'">
|
|
|
<u-input type="textarea" :placeholder="item.help?item.help:'请输入'" v-model="item.value" />
|
|
|
</block> -->
|
|
|
<u-input :type="'textarea'" maxlength="9999" :placeholder="item.help?item.help:'请输入'" v-model="item.value" />
|
|
|
</block>
|
|
|
<block v-else-if="item.edit_input==='radio'">
|
|
|
<u-input :placeholder="item.help?item.help:'请选择'" v-model="item.value" :type="'select'"
|
|
|
@click="showSelect(item,index)" />
|
|
|
</block>
|
|
|
<block v-else-if="item.edit_input==='checkbox'">
|
|
|
<u-input
|
|
|
:value="getCheckboxDisplayValue(item)"
|
|
|
:placeholder="item.help?item.help:'请选择'"
|
|
|
type="select"
|
|
|
@click="openCheckboxModal(item, index)"
|
|
|
border
|
|
|
/>
|
|
|
</block>
|
|
|
<block v-else-if="item.edit_input==='date'">
|
|
|
<u-input :placeholder="item.help?item.help:'请选择'" v-model="item.value" :type="'select'"
|
|
|
@click="showDate(item,index)" />
|
|
|
</block>
|
|
|
<block v-else-if="item.edit_input==='datetime'">
|
|
|
<u-input :placeholder="item.help?item.help:'请选择'" v-model="item.value" :type="'select'"
|
|
|
@click="showDateTime(item,index)" />
|
|
|
</block>
|
|
|
<block v-else-if="item.edit_input==='files'">
|
|
|
<view class="file-upload-wrapper">
|
|
|
<view class="file-upload-btn" @click="chooseFile(item)">
|
|
|
<u-icon name="plus" size="40" color="#2979ff" />
|
|
|
<text class="file-upload-btn__text">上传文件</text>
|
|
|
</view>
|
|
|
<!-- 文件/图片列表展示 -->
|
|
|
<view
|
|
|
class="file-list"
|
|
|
v-if="item.fileListArr && item.fileListArr.length > 0"
|
|
|
>
|
|
|
<block v-for="(file, fIndex) in item.fileListArr" :key="fIndex">
|
|
|
<!-- 图片预览 -->
|
|
|
<view
|
|
|
v-if="isImageFile(file)"
|
|
|
class="file-list__image-wrapper"
|
|
|
@click="previewImageFile(file, item)"
|
|
|
>
|
|
|
<image
|
|
|
class="file-list__image"
|
|
|
:src="getFileUrl(file)"
|
|
|
mode="aspectFill"
|
|
|
/>
|
|
|
<view class="file-list__delete" @click.stop="removeFile(fIndex, item)">
|
|
|
<u-icon name="close" size="20" color="#fff" />
|
|
|
</view>
|
|
|
</view>
|
|
|
<!-- 普通文件预览 -->
|
|
|
<view
|
|
|
v-else
|
|
|
class="file-list__file"
|
|
|
>
|
|
|
<u-icon name="file-text" size="36" color="#2979ff" />
|
|
|
<text class="file-list__file-name">{{ getFileName(file) }}</text>
|
|
|
<view class="file-list__delete" @click.stop="removeFile(fIndex, item)">
|
|
|
<u-icon name="close" size="20" color="#fff" />
|
|
|
</view>
|
|
|
</view>
|
|
|
</block>
|
|
|
</view>
|
|
|
</view>
|
|
|
</block>
|
|
|
</u-form-item>
|
|
|
</block>
|
|
|
</u-form>
|
|
|
<view class="form-btn">
|
|
|
<view @click="submit" type="primary">提交</view>
|
|
|
</view>
|
|
|
<!-- 单选 -->
|
|
|
<u-picker @confirm="selectConfirm" v-model="selectShow" :range="selectList" range-key="value"
|
|
|
mode="selector"></u-picker>
|
|
|
<!-- 日期 -->
|
|
|
<u-picker @confirm="dateConfirm" mode="time" v-model="dateShow" :params="dateParams"></u-picker>
|
|
|
<!-- 日期时间 -->
|
|
|
<u-picker @confirm="dateTimeConfirm" mode="time" v-model="dateTimeShow" :params="dateTimeParams"></u-picker>
|
|
|
<!-- 公司选择器 -->
|
|
|
<company-selector v-model="showCompanySelector" @confirm="handleCompanyConfirm" @no-data="handleNoCompanyData"></company-selector>
|
|
|
<!-- 手动输入公司名称 -->
|
|
|
<view class="modal">
|
|
|
<u-popup v-model="showCompanyInput" mode="bottom">
|
|
|
<view class="modal-tip">输入公司名称</view>
|
|
|
<view class="modal-content" style="height:400rpx">
|
|
|
<view class="login-form">
|
|
|
<view>
|
|
|
<u-input :custom-style="inputStyle" :clearable="true" v-model="manualCompanyName"
|
|
|
placeholder="请输入公司全称"></u-input>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
<view class="form-btn">
|
|
|
<view @click="confirmManualCompany" type="primary">确定</view>
|
|
|
</view>
|
|
|
</u-popup>
|
|
|
</view>
|
|
|
<!-- 多选弹窗 -->
|
|
|
<u-popup v-model="showCheckboxModal" mode="bottom" border-radius="20">
|
|
|
<view class="checkbox-modal">
|
|
|
<view class="checkbox-modal__header">
|
|
|
<text class="checkbox-modal__title">{{ currentCheckboxItem.name || '请选择' }}</text>
|
|
|
<text class="checkbox-modal__close" @click="showCheckboxModal = false">完成</text>
|
|
|
</view>
|
|
|
<scroll-view
|
|
|
class="checkbox-modal__content"
|
|
|
scroll-y="true"
|
|
|
:style="{ height: checkboxContentHeight + 'px' }"
|
|
|
>
|
|
|
<checkbox-group @change="(e)=>{checkboxGroupChange(e, currentCheckboxItem)}">
|
|
|
<label
|
|
|
class="checkbox-modal__item"
|
|
|
v-for="(checkboxitem, checkboxindex) in currentCheckboxItem.select_item"
|
|
|
:key="checkboxindex"
|
|
|
>
|
|
|
<checkbox
|
|
|
class="checkbox-modal__control"
|
|
|
:value="checkboxitem.value"
|
|
|
:checked="checkboxitem.checked"
|
|
|
/>
|
|
|
<text class="checkbox-modal__label">{{checkboxitem.value}}</text>
|
|
|
</label>
|
|
|
</checkbox-group>
|
|
|
</scroll-view>
|
|
|
</view>
|
|
|
</u-popup>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
// import { watch } from "vue"
|
|
|
import {
|
|
|
ROOTPATH as baseUrl
|
|
|
} from "@/common/config.js"
|
|
|
import CompanySelector from '@/components/company-selector/company-selector.vue'
|
|
|
export default {
|
|
|
components: {
|
|
|
CompanySelector
|
|
|
},
|
|
|
props: {
|
|
|
course_forms: {
|
|
|
type: Array,
|
|
|
default () {
|
|
|
return []
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
showCompanySelector: false,
|
|
|
showCompanyInput: false,
|
|
|
manualCompanyName: '',
|
|
|
submitForm: {},
|
|
|
now_fileld: 0, // 当前所操作的 filed index值
|
|
|
// 单选
|
|
|
selectShow: false,
|
|
|
selectList: [],
|
|
|
// 多选弹窗
|
|
|
showCheckboxModal: false,
|
|
|
currentCheckboxItem: {},
|
|
|
currentCheckboxIndex: 0,
|
|
|
checkboxContentHeight: 400, // 多选弹窗内容区域高度,单位px
|
|
|
// 日期
|
|
|
dateShow: false,
|
|
|
dateParams: {
|
|
|
year: true,
|
|
|
month: true,
|
|
|
day: true,
|
|
|
hour: false,
|
|
|
minute: false,
|
|
|
second: false
|
|
|
},
|
|
|
// 日期时间
|
|
|
dateTimeShow: false,
|
|
|
dateTimeParams: {
|
|
|
year: true,
|
|
|
month: true,
|
|
|
day: true,
|
|
|
hour: true,
|
|
|
minute: true,
|
|
|
second: true
|
|
|
},
|
|
|
// 文件上传
|
|
|
action: `${baseUrl}/api/mobile/upload-file`,
|
|
|
fileList: [],
|
|
|
formData: {},
|
|
|
rules: {},
|
|
|
// 手动输入公司名称样式
|
|
|
inputStyle: {
|
|
|
'padding': '0rpx 30rpx',
|
|
|
'height': '80rpx',
|
|
|
'border': '1rpx solid #dad8d8;',
|
|
|
'border-radius': '20rpx'
|
|
|
},
|
|
|
|
|
|
|
|
|
}
|
|
|
},
|
|
|
onReady() {
|
|
|
// this.$refs.uForm.setRules(this.rules);
|
|
|
let token = uni.getStorageSync("stbc1_lifeData").vuex_token
|
|
|
console.log("token", token)
|
|
|
this.formData = {
|
|
|
token: token
|
|
|
}
|
|
|
this.calculateCheckboxHeight()
|
|
|
},
|
|
|
onLoad() {
|
|
|
|
|
|
},
|
|
|
methods: {
|
|
|
// 处理公司选择确认事件
|
|
|
handleCompanyConfirm(company) {
|
|
|
console.log('选中的公司:', company);
|
|
|
this.course_forms.map(item1 => {
|
|
|
if (item1.field === 'company_name') {
|
|
|
this.$set(item1,'value',company.enterpriseName||'')
|
|
|
}
|
|
|
if (item1.field === 'company_date') {
|
|
|
this.$set(item1,'value',company.startDate||'')
|
|
|
}
|
|
|
if (item1.field === 'company_product') {
|
|
|
this.$set(item1,'value',company.businessScope||'')
|
|
|
}
|
|
|
if (item1.field === 'company_type') {
|
|
|
const company_type = company.tagList && Array.isArray(company.tagList)?company.tagList.join(','):''
|
|
|
const _arr = company_type.split(',')
|
|
|
this.$set(item1,'value',company_type)
|
|
|
item1.select_item.forEach(item2 => {
|
|
|
console.log("item2",item2)
|
|
|
// 检查 item.value 是否存在于数组 b 中
|
|
|
const exists = _arr.includes(item2.value);
|
|
|
// 根据检查结果设置 checked 属性
|
|
|
item2.checked = exists;
|
|
|
this.$set(item2,'checked',exists)
|
|
|
});
|
|
|
|
|
|
}
|
|
|
if (item1.field === 'company_area') {
|
|
|
this.$set(item1,'value',company.country||'')
|
|
|
}
|
|
|
if (item1.field === 'company_address') {
|
|
|
this.$set(item1,'value',company.address||'')
|
|
|
}
|
|
|
if (item1.field === 'is_yuanhe') {
|
|
|
this.$set(item1,'value',company.isYhInvested?'是':'否')
|
|
|
}
|
|
|
})
|
|
|
console.log("this.course_forms",this.course_forms)
|
|
|
},
|
|
|
// 处理搜索无数据事件
|
|
|
handleNoCompanyData(searchKeyword) {
|
|
|
uni.showModal({
|
|
|
title: '提示',
|
|
|
content: '当前没有查询到公司信息,是否输入公司全称?',
|
|
|
success: (res) => {
|
|
|
if (res.confirm) {
|
|
|
// 关闭搜索窗口
|
|
|
this.showCompanySelector = false;
|
|
|
// 设置默认值为搜索关键词
|
|
|
this.manualCompanyName = searchKeyword || '';
|
|
|
// 打开输入框
|
|
|
this.showCompanyInput = true;
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
// 确认手动输入的公司名称
|
|
|
confirmManualCompany() {
|
|
|
if (this.base.isNull(this.manualCompanyName)) {
|
|
|
this.base.toast('请输入公司名称');
|
|
|
return;
|
|
|
}
|
|
|
// 将输入的公司名称赋给 course_forms 中 field === 'company_name' 的项的 value
|
|
|
this.course_forms.map(item1 => {
|
|
|
if (item1.field === 'company_name') {
|
|
|
this.$set(item1, 'value', this.manualCompanyName.trim());
|
|
|
}
|
|
|
});
|
|
|
// 关闭输入框
|
|
|
this.showCompanyInput = false;
|
|
|
// 清空输入
|
|
|
this.manualCompanyName = '';
|
|
|
},
|
|
|
// 单选
|
|
|
showSelect(item, index) {
|
|
|
this.selectList = item.select_item
|
|
|
this.now_fileld = index
|
|
|
this.selectShow = true
|
|
|
},
|
|
|
selectConfirm(e) {
|
|
|
this.course_forms[this.now_fileld]['value'] = this.selectList[e[0]].value
|
|
|
},
|
|
|
// 多选 - 获取显示值
|
|
|
getCheckboxDisplayValue(item) {
|
|
|
if (!item.value || this.base.isNull(item.value)) {
|
|
|
return ''
|
|
|
}
|
|
|
const selectedValues = item.value.split(',')
|
|
|
// 最多显示3个,超过显示"等X项"
|
|
|
if (selectedValues.length <= 3) {
|
|
|
return selectedValues.join('、')
|
|
|
} else {
|
|
|
return selectedValues.slice(0, 3).join('、') + `等${selectedValues.length}项`
|
|
|
}
|
|
|
},
|
|
|
// 显示多选弹窗
|
|
|
openCheckboxModal(item, index) {
|
|
|
this.currentCheckboxItem = item
|
|
|
this.currentCheckboxIndex = index
|
|
|
this.showCheckboxModal = true
|
|
|
this.$nextTick(() => {
|
|
|
this.calculateCheckboxHeight()
|
|
|
})
|
|
|
},
|
|
|
// 计算多选弹窗内容区域高度
|
|
|
calculateCheckboxHeight() {
|
|
|
uni.getSystemInfo({
|
|
|
success: (res) => {
|
|
|
// 屏幕高度的 60%,减去 header 的高度
|
|
|
const maxHeight = res.windowHeight * 0.6
|
|
|
// header 大约 100rpx,转换为 px
|
|
|
const headerHeight = 100 * (res.windowWidth / 750)
|
|
|
// content 高度 = 最大高度 - header - 底部 padding
|
|
|
this.checkboxContentHeight = maxHeight - headerHeight - 80
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
// 多选
|
|
|
checkboxGroupChange(e, item) {
|
|
|
const selectedValues = e.detail.value || []
|
|
|
if (selectedValues.length > 0) {
|
|
|
item.value = selectedValues.join(",")
|
|
|
} else {
|
|
|
item.value = ''
|
|
|
}
|
|
|
// 更新checked状态
|
|
|
item.select_item.forEach(option => {
|
|
|
option.checked = selectedValues.includes(option.value)
|
|
|
this.$set(option, 'checked', selectedValues.includes(option.value))
|
|
|
})
|
|
|
},
|
|
|
// 日期
|
|
|
showDate(item, index) {
|
|
|
this.now_fileld = index
|
|
|
this.dateShow = true
|
|
|
},
|
|
|
dateConfirm(e) {
|
|
|
console.log("date", e)
|
|
|
this.course_forms[this.now_fileld]['value'] = e.year + '-' + e.month + '-' + e.day
|
|
|
},
|
|
|
// 日期时间
|
|
|
showDateTime(item, index) {
|
|
|
this.now_fileld = index
|
|
|
this.dateTimeShow = true
|
|
|
},
|
|
|
dateTimeConfirm(e) {
|
|
|
console.log("date", e)
|
|
|
this.course_forms[this.now_fileld]['value'] = e.year + '-' + e.month + '-' + e.day +
|
|
|
' ' + e.hour + ':' + e.minute + ':' + e.second
|
|
|
},
|
|
|
// 根据文件对象获取真实 url
|
|
|
getFileUrl(file) {
|
|
|
if (!file) return ''
|
|
|
let url = ''
|
|
|
if (file.response && file.response.url) {
|
|
|
url = file.response.url
|
|
|
} else if (file.url) {
|
|
|
url = file.url
|
|
|
}
|
|
|
// 如果是相对路径,补全域名
|
|
|
if (url && url.indexOf('http') !== 0) {
|
|
|
url = baseUrl + url
|
|
|
}
|
|
|
return url || ''
|
|
|
},
|
|
|
// 判断是否为图片文件
|
|
|
isImageFile(file) {
|
|
|
if (!file) return false
|
|
|
const url = this.getFileUrl(file)
|
|
|
if (!url) return false
|
|
|
return /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(url)
|
|
|
},
|
|
|
// 预览图片
|
|
|
previewImageFile(file, item) {
|
|
|
const current = this.getFileUrl(file)
|
|
|
const urls = (item.fileListArr || [])
|
|
|
.filter(f => this.isImageFile(f))
|
|
|
.map(f => this.getFileUrl(f))
|
|
|
if (!urls.length) return
|
|
|
uni.previewImage({
|
|
|
current,
|
|
|
urls
|
|
|
})
|
|
|
},
|
|
|
// 获取文件名
|
|
|
getFileName(file) {
|
|
|
// 优先使用 original_name,其次使用 name,最后从 url 提取
|
|
|
if (file.response && file.response.original_name) {
|
|
|
return file.response.original_name
|
|
|
}
|
|
|
if (file.name) {
|
|
|
return file.name
|
|
|
}
|
|
|
const url = this.getFileUrl(file)
|
|
|
if (!url) return '未知文件'
|
|
|
const parts = url.split('/')
|
|
|
return parts[parts.length - 1]
|
|
|
},
|
|
|
// 打开普通文件(pdf/doc/xls 等)
|
|
|
openFile(file) {
|
|
|
const url = this.getFileUrl(file)
|
|
|
if (!url) return
|
|
|
uni.showLoading({
|
|
|
title: '打开中...',
|
|
|
mask: true
|
|
|
})
|
|
|
uni.downloadFile({
|
|
|
url,
|
|
|
success: (res) => {
|
|
|
if (res.statusCode === 200) {
|
|
|
uni.openDocument({
|
|
|
filePath: res.tempFilePath,
|
|
|
success: () => {},
|
|
|
fail: (err) => {
|
|
|
console.error('openDocument 失败', err)
|
|
|
this.base && this.base.toast && this.base.toast('无法打开文件')
|
|
|
},
|
|
|
complete: () => {
|
|
|
uni.hideLoading()
|
|
|
}
|
|
|
})
|
|
|
} else {
|
|
|
uni.hideLoading()
|
|
|
this.base && this.base.toast && this.base.toast('文件下载失败')
|
|
|
}
|
|
|
},
|
|
|
fail: (err) => {
|
|
|
console.error('downloadFile 失败', err)
|
|
|
uni.hideLoading()
|
|
|
this.base && this.base.toast && this.base.toast('文件下载失败')
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
// 选择文件(支持图片和普通文件)
|
|
|
chooseFile(item) {
|
|
|
uni.showActionSheet({
|
|
|
itemList: ['选择图片', '选择文件'],
|
|
|
success: (res) => {
|
|
|
if (res.tapIndex === 0) {
|
|
|
// 选择图片
|
|
|
uni.chooseImage({
|
|
|
count: 9 - (item.fileListArr ? item.fileListArr.length : 0),
|
|
|
success: (res) => {
|
|
|
this.uploadFiles(res.tempFilePaths, item, 'image')
|
|
|
}
|
|
|
})
|
|
|
} else if (res.tapIndex === 1) {
|
|
|
// 选择文件 - 使用平台特定的API
|
|
|
const maxCount = 9 - (item.fileListArr ? item.fileListArr.length : 0)
|
|
|
// #ifdef MP-WEIXIN
|
|
|
// 微信小程序使用 wx.chooseMessageFile
|
|
|
if (typeof wx !== 'undefined' && wx.chooseMessageFile) {
|
|
|
wx.chooseMessageFile({
|
|
|
count: maxCount,
|
|
|
type: 'file',
|
|
|
success: (res) => {
|
|
|
const filePaths = res.tempFiles.map(f => f.path)
|
|
|
this.uploadFiles(filePaths, item, 'file')
|
|
|
},
|
|
|
fail: (err) => {
|
|
|
console.error('选择文件失败', err)
|
|
|
this.base && this.base.toast && this.base.toast('选择文件失败')
|
|
|
}
|
|
|
})
|
|
|
} else {
|
|
|
// 降级方案:提示用户使用图片选择
|
|
|
uni.showModal({
|
|
|
title: '提示',
|
|
|
content: '当前平台暂不支持选择文件,请使用图片上传功能',
|
|
|
showCancel: false
|
|
|
})
|
|
|
}
|
|
|
// #endif
|
|
|
// #ifndef MP-WEIXIN
|
|
|
// 其他平台尝试使用 uni.chooseFile(如果支持)
|
|
|
if (typeof uni.chooseFile === 'function') {
|
|
|
uni.chooseFile({
|
|
|
count: maxCount,
|
|
|
success: (res) => {
|
|
|
const filePaths = res.tempFiles ? res.tempFiles.map(f => f.path) : []
|
|
|
this.uploadFiles(filePaths, item, 'file')
|
|
|
},
|
|
|
fail: (err) => {
|
|
|
console.error('选择文件失败', err)
|
|
|
// 降级:使用图片选择API
|
|
|
uni.showModal({
|
|
|
title: '提示',
|
|
|
content: '当前平台暂不支持选择文件,请使用图片上传功能',
|
|
|
showCancel: false
|
|
|
})
|
|
|
}
|
|
|
})
|
|
|
} else {
|
|
|
// 不支持文件选择,提示用户
|
|
|
uni.showModal({
|
|
|
title: '提示',
|
|
|
content: '当前平台暂不支持选择文件,请使用图片上传功能',
|
|
|
showCancel: false
|
|
|
})
|
|
|
}
|
|
|
// #endif
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
// 上传文件
|
|
|
uploadFiles(filePaths, item, type) {
|
|
|
// 找到对应的 course_forms 中的 item
|
|
|
const formItem = this.course_forms.find(f => f.field === item.field)
|
|
|
if (!formItem) {
|
|
|
console.error('找不到对应的表单字段', item.field)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if (!formItem.fileListArr) {
|
|
|
this.$set(formItem, 'fileListArr', [])
|
|
|
}
|
|
|
|
|
|
let uploadCount = 0
|
|
|
let successCount = 0
|
|
|
const totalCount = filePaths.length
|
|
|
|
|
|
if (totalCount === 0) return
|
|
|
|
|
|
uni.showLoading({
|
|
|
title: '上传中...',
|
|
|
mask: true
|
|
|
})
|
|
|
|
|
|
filePaths.forEach((filePath, index) => {
|
|
|
uni.uploadFile({
|
|
|
url: this.action,
|
|
|
filePath: filePath,
|
|
|
name: 'file',
|
|
|
formData: this.formData,
|
|
|
success: (res) => {
|
|
|
uploadCount++
|
|
|
try {
|
|
|
const result = JSON.parse(res.data)
|
|
|
// 兼容两种返回格式:
|
|
|
// 1. 直接返回对象 {id, url, ...}
|
|
|
// 2. 包装格式 {code: 200, data: {id, url, ...}}
|
|
|
let data = result
|
|
|
if (result.code === 200 && result.data) {
|
|
|
data = result.data
|
|
|
}
|
|
|
|
|
|
if (data && data.url) {
|
|
|
const fileObj = {
|
|
|
url: data.url,
|
|
|
response: data,
|
|
|
name: data.original_name || filePath.split('/').pop()
|
|
|
}
|
|
|
// 确保 fileListArr 存在
|
|
|
if (!formItem.fileListArr) {
|
|
|
this.$set(formItem, 'fileListArr', [])
|
|
|
}
|
|
|
// 使用 Vue.set 确保响应式更新
|
|
|
formItem.fileListArr.push(fileObj)
|
|
|
// 强制触发视图更新 - 创建新数组引用
|
|
|
this.$set(formItem, 'fileListArr', formItem.fileListArr.slice())
|
|
|
// 强制更新视图
|
|
|
this.$forceUpdate()
|
|
|
successCount++
|
|
|
|
|
|
console.log('上传成功', fileObj)
|
|
|
console.log('formItem.fileListArr', formItem.fileListArr)
|
|
|
console.log('formItem.field', formItem.field)
|
|
|
console.log('item.field', item.field)
|
|
|
} else {
|
|
|
console.error('上传响应格式错误,缺少url字段', result)
|
|
|
if (uploadCount === totalCount) {
|
|
|
this.base && this.base.toast && this.base.toast('部分文件上传失败')
|
|
|
}
|
|
|
}
|
|
|
} catch (e) {
|
|
|
console.error('解析上传响应失败', e, res.data)
|
|
|
if (uploadCount === totalCount) {
|
|
|
this.base && this.base.toast && this.base.toast('部分文件上传失败')
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 所有文件上传完成
|
|
|
if (uploadCount === totalCount) {
|
|
|
uni.hideLoading()
|
|
|
if (successCount > 0) {
|
|
|
this.base && this.base.toast && this.base.toast(`成功上传${successCount}个文件`)
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
fail: (err) => {
|
|
|
uploadCount++
|
|
|
console.error('上传失败', err)
|
|
|
if (uploadCount === totalCount) {
|
|
|
uni.hideLoading()
|
|
|
this.base && this.base.toast && this.base.toast('上传失败')
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
})
|
|
|
},
|
|
|
// 删除文件
|
|
|
removeFile(index, item) {
|
|
|
uni.showModal({
|
|
|
title: '提示',
|
|
|
content: '确定要删除这个文件吗?',
|
|
|
success: (res) => {
|
|
|
if (res.confirm) {
|
|
|
// 找到对应的 course_forms 中的 item
|
|
|
const formItem = this.course_forms.find(f => f.field === item.field)
|
|
|
if (formItem && formItem.fileListArr) {
|
|
|
formItem.fileListArr.splice(index, 1)
|
|
|
// 强制触发视图更新
|
|
|
this.$set(formItem, 'fileListArr', [...formItem.fileListArr])
|
|
|
console.log('删除文件后', formItem.fileListArr)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
// 提交
|
|
|
submit() {
|
|
|
console.log("course_forms", this.course_forms)
|
|
|
let errorCount = 0
|
|
|
this.course_forms.map(item => {
|
|
|
if (item.rule) {
|
|
|
// 不能为空
|
|
|
if (item.rule.indexOf('required') !== -1) {
|
|
|
if (this.base.isNull(item.value)) {
|
|
|
this.base.toast(`${item.name}不能为空`)
|
|
|
errorCount++
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
// 手机号
|
|
|
if (!this.base.isNull(item.value) && item.rule.indexOf('mobile') !== -1) {
|
|
|
if (!this.base.isMobile(item.value)) {
|
|
|
this.base.toast(`${item.name}不正确`)
|
|
|
errorCount++
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
// 身份证
|
|
|
if (!this.base.isNull(item.value) && item.rule.indexOf('idcard') !== -1) {
|
|
|
if (!this.$u.test.idCard(item.value)) {
|
|
|
this.base.toast(`${item.name}不正确`)
|
|
|
errorCount++
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
// 邮箱
|
|
|
if (item.rule.indexOf('email') !== -1) {
|
|
|
if (!this.base.isNull(item.value) && !this.base.isMail(item.value)) {
|
|
|
this.base.toast(`${item.name}不正确`)
|
|
|
errorCount++
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
// 整数
|
|
|
if (item.rule.indexOf('integer') !== -1) {
|
|
|
if (!this.base.isNull(item.value) && !this.base.isInteger(item.value)) {
|
|
|
this.base.toast(`${item.name}必须为整数`)
|
|
|
errorCount++
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
// 数字
|
|
|
if (item.rule.indexOf('numeric') !== -1) {
|
|
|
if (!this.base.isNull(item.value) && !this.base.isNumber(item.value)) {
|
|
|
this.base.toast(`${item.name}必须为数字`)
|
|
|
errorCount++
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 文件上传处理
|
|
|
if(item.edit_input==='files'){
|
|
|
let valueArr = []
|
|
|
let fileListArr = []
|
|
|
console.log("item.fileListArr",item.fileListArr)
|
|
|
if(item.fileListArr && item.fileListArr.length>0){
|
|
|
item.fileListArr.map(f=>{
|
|
|
if(f.response){
|
|
|
valueArr.push(f.response.url.replace(baseUrl, ''))
|
|
|
fileListArr.push(f.response)
|
|
|
}else{
|
|
|
valueArr.push(f.url.replace(baseUrl, ''))
|
|
|
fileListArr.push(f)
|
|
|
}
|
|
|
})
|
|
|
}else{
|
|
|
item.fileListArr = []
|
|
|
}
|
|
|
item.value = valueArr.join(",")
|
|
|
item.fileList = fileListArr
|
|
|
console.log("submit---",valueArr,fileListArr)
|
|
|
}
|
|
|
})
|
|
|
if (errorCount > 0) {
|
|
|
return
|
|
|
} else {
|
|
|
// return
|
|
|
this.$emit("backForm", this.course_forms)
|
|
|
}
|
|
|
},
|
|
|
},
|
|
|
watch: {
|
|
|
course_forms(newval) {
|
|
|
if (newval) {
|
|
|
// 验证规则
|
|
|
let that = this
|
|
|
let _rule = {}
|
|
|
newval.map(item => {
|
|
|
if (item.edit_input === 'checkbox') {
|
|
|
// 修改有值的时候 先split
|
|
|
let _arr = []
|
|
|
if (!this.base.isNull(item.value)) {
|
|
|
_arr = item.value.split(",")
|
|
|
console.log("_arr", _arr)
|
|
|
item.select_item.forEach(item1 => {
|
|
|
// 检查 item.value 是否存在于数组 b 中
|
|
|
const exists = _arr.includes(item1.value);
|
|
|
// 根据检查结果设置 checked 属性
|
|
|
item1.checked = exists;
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
if (item.edit_input === 'files') {
|
|
|
item.fileListArr = this.base.deepCopy(item.fileList)
|
|
|
}
|
|
|
})
|
|
|
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
.applyform {
|
|
|
position: relative;
|
|
|
z-index: 99
|
|
|
}
|
|
|
|
|
|
.form-btn {
|
|
|
width: 100%;
|
|
|
position: relative;
|
|
|
padding: 60rpx 0;
|
|
|
|
|
|
&>view {
|
|
|
width: 70%;
|
|
|
text-align: center;
|
|
|
margin: 0 auto;
|
|
|
color: #fff;
|
|
|
background: linear-gradient(to right, #5e5fbc, #0d0398);
|
|
|
border-radius: 30rpx;
|
|
|
padding: 20rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.modal {
|
|
|
::v-deep .u-drawer-bottom {
|
|
|
border-radius: 40rpx;
|
|
|
}
|
|
|
|
|
|
&-tip {
|
|
|
text-align: center;
|
|
|
padding: 30rpx;
|
|
|
font-size: 32rpx;
|
|
|
}
|
|
|
|
|
|
&-content {
|
|
|
padding: 0 30rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.login-form {
|
|
|
margin: 100rpx 50rpx;
|
|
|
|
|
|
&>view {
|
|
|
border-radius: 20rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 多选项布局优化 */
|
|
|
.checkbox-group {
|
|
|
display: flex;
|
|
|
flex-wrap: wrap;
|
|
|
}
|
|
|
|
|
|
.checkbox-item {
|
|
|
width: 48%;
|
|
|
margin-bottom: 16rpx;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
padding: 12rpx 20rpx;
|
|
|
box-sizing: border-box;
|
|
|
border-radius: 12rpx;
|
|
|
border: 1rpx solid #e0e0e0;
|
|
|
background-color: #f9f9f9;
|
|
|
}
|
|
|
|
|
|
.checkbox-item__control {
|
|
|
transform: scale(0.9);
|
|
|
}
|
|
|
|
|
|
.checkbox-item__label {
|
|
|
margin-left: 12rpx;
|
|
|
font-size: 26rpx;
|
|
|
color: #333;
|
|
|
}
|
|
|
|
|
|
/* 多选弹窗样式 */
|
|
|
.checkbox-modal {
|
|
|
background-color: #fff;
|
|
|
border-radius: 20rpx 20rpx 0 0;
|
|
|
max-height: 80vh;
|
|
|
|
|
|
&__header {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
padding: 30rpx;
|
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
|
}
|
|
|
|
|
|
&__title {
|
|
|
font-size: 32rpx;
|
|
|
font-weight: 600;
|
|
|
color: #333;
|
|
|
}
|
|
|
|
|
|
&__close {
|
|
|
font-size: 28rpx;
|
|
|
color: #2979ff;
|
|
|
}
|
|
|
|
|
|
&__content {
|
|
|
padding: 20rpx 30rpx 40rpx;
|
|
|
box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
&__item {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
padding: 24rpx 0;
|
|
|
padding-left: 10rpx; // 增加左侧 padding,确保 checkbox 不被遮挡
|
|
|
border-bottom: 1rpx solid #f5f5f5;
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
&:last-child {
|
|
|
border-bottom: none;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
&__control {
|
|
|
transform: scale(1.1);
|
|
|
flex-shrink: 0; // 防止 checkbox 被压缩
|
|
|
}
|
|
|
|
|
|
&__label {
|
|
|
margin-left: 20rpx;
|
|
|
font-size: 28rpx;
|
|
|
color: #333;
|
|
|
flex: 1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 文件上传样式 */
|
|
|
.file-upload-wrapper {
|
|
|
width: 100%;
|
|
|
}
|
|
|
|
|
|
.file-upload-btn {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
width: 160rpx;
|
|
|
height: 160rpx;
|
|
|
border: 2rpx dashed #d0d0d0;
|
|
|
border-radius: 12rpx;
|
|
|
background-color: #fafafa;
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
&__text {
|
|
|
margin-top: 10rpx;
|
|
|
font-size: 24rpx;
|
|
|
color: #666;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.file-list {
|
|
|
display: flex;
|
|
|
flex-wrap: wrap;
|
|
|
gap: 20rpx;
|
|
|
margin-top: 20rpx;
|
|
|
|
|
|
&__image-wrapper {
|
|
|
position: relative;
|
|
|
width: 160rpx;
|
|
|
height: 160rpx;
|
|
|
border-radius: 12rpx;
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
|
|
|
&__image {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
}
|
|
|
|
|
|
&__file {
|
|
|
position: relative;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
width: 160rpx;
|
|
|
height: 160rpx;
|
|
|
border: 1rpx solid #e0e0e0;
|
|
|
border-radius: 12rpx;
|
|
|
background-color: #f9f9f9;
|
|
|
padding: 20rpx;
|
|
|
box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
&__file-name {
|
|
|
margin-top: 10rpx;
|
|
|
font-size: 22rpx;
|
|
|
color: #666;
|
|
|
text-align: center;
|
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
|
white-space: nowrap;
|
|
|
width: 100%;
|
|
|
}
|
|
|
|
|
|
&__delete {
|
|
|
position: absolute;
|
|
|
top: -10rpx;
|
|
|
right: -10rpx;
|
|
|
width: 40rpx;
|
|
|
height: 40rpx;
|
|
|
background-color: #ff4444;
|
|
|
border-radius: 50%;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
}
|
|
|
</style> |