123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- <template>
- <view>
- <!-- 动态生成的报销详情表单 -->
- <u-form>
- <!-- 动态生成的普通表单 -->
- <el-row :gutter="15">
- <el-col :span="24">
- <div class="form-grid">
- <div v-for="(grid, gridIndex) in gridsTest" :key="grid.key">
- <div v-for="(col, colIndex) in grid.columns" :key="col.key" class="form-column">
- <div v-for="(field, fieldIndex) in col.list" :key="field.key" class="form-field">
- <div v-if="field.type === 'input'" class="form-item">
- <text>{{ field.name }}:</text>
- <input
- v-model="formModel[field.model]"
- :placeholder="field.options.placeholder"
- :disabled="field.options.disabled"
- :maxlength="field.options.maxlength"
- :class="{'input-field': true, 'input-disabled': field.options.disabled}"
- />
- </div>
- <div v-if="field.type === 'textarea'" class="form-item">
- <text>{{ field.name }}:</text>
- <textarea
- v-model="formModel[field.model]"
- :placeholder="field.options.placeholder"
- :disabled="field.options.disabled"
- :rows="field.options.rows || 2"
- :class="{'textarea-field': true, 'textarea-disabled': field.options.disabled}"
- />
- </div>
- </div>
- </div>
- </div>
- </div>
- </el-col>
- </el-row>
- <el-row :gutter="15" v-for="(item, index_experience) in formModelDetail" :key="index_experience">
- <el-col :span="24">
- <u-form-item label="">
- <u-divider :text="'报销详情 ' + (index_experience + 1)"></u-divider>
- </u-form-item>
- </el-col>
- <el-col :span="24" v-for="(column, colIndex) in gridsDetail[0].tableColumns" :key="colIndex">
- <u-form-item :label="column.name" :prop="`formModelDetail[${index_experience}].${column.model}`">
- <template v-if="column.type === 'text'">
- <u-input v-model="formModelDetail[index_experience][column.model]" :disabled="true" placeholder="" clearable></u-input>
- </template>
- <template v-else-if="column.type === 'date'">
- <el-date-picker v-model="formModelDetail[index_experience][column.model]" :disabled="true" type="date" style="width:100%" size="default" placement="bottom-start" clearable></el-date-picker>
- </template>
- </u-form-item>
- </el-col>
- </el-row>
- <!-- 动态生成专用发票信息 -->
- <el-row :gutter="15" v-for="(item, invoice_index) in invoiceFormModelDetail" :key="invoice_index">
- <el-col :span="24">
- <u-form-item label="">
- <u-divider :text="'专用发票信息 ' + (invoice_index + 1)"></u-divider>
- </u-form-item>
- </el-col>
- <el-col :span="24" v-for="(column, colIndex) in gridsInvoice[0].tableColumns" :key="colIndex">
- <u-form-item :label="column.name" :prop="`invoiceFormModelDetail[${invoice_index}].${column.model}`">
- <template v-if="column.type === 'text'">
- <u-input v-model="invoiceFormModelDetail[invoice_index][column.model]" :disabled="true" placeholder="" clearable></u-input>
- </template>
- <template v-else-if="column.type === 'date'">
- <el-date-picker v-model="invoiceFormModelDetail[invoice_index][column.model]" :disabled="true" type="date" style="width:100%" size="default" placement="bottom-start" clearable></el-date-picker>
- </template>
- </u-form-item>
- </el-col>
- </el-row>
- <u-form-item label="附件">
- <el-upload
- class="upload-demo"
- :action="`http://pk2cs5.natappfree.cc/api/public-modules-server/oss/file/webUpload/upload`"
- :on-remove="(file, fileList) => handleRemove(file, fileList,'')"
- :file-list="files"
- :on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList,'')"
- :limit="3">
- <el-button size="small" type="primary" v-if="false">点击上传</el-button>
- <div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
- <template slot="file" slot-scope="{ file }" v-if="shouldShowFile(file)">
- <span @click="handleFileClick(file)">{{ file.name }}</span>
- <!-- <el-button type="text" @click="handleDelete(file,'')"> ✕ </el-button>-->
- </template>
- </el-upload>
- </u-form-item>
- </u-form>
- </view>
- </template>
- <script>
- import OSSService from "@/api/sys/OSSService"
- export default {
- name: 'DynamicForm',
- props: {
- grids: {
- type: Array,
- required: true
- },
- },
- data() {
- return {
- gridsTest: [],
- gridsDetail: [],
- gridsInvoice: [],
- formModel: {},
- formModelDetail: [],
- invoiceFormModelDetail: [],
- files: [],
- showFileList: []
- };
- },
- ossService: null,
- created() {
- this.ossService = new OSSService()
- },
- watch: {
- grids: {
- handler(newVal) {
- this.initializeFormModel();
- },
- deep: true,
- immediate: true
- }
- },
- methods: {
- initializeFormModel() {
- this.files = this.grids.files
- if (this.files) {
- this.files.forEach( (item,index) => {
- this.$set(this.showFileList, index, true);
- })
- }
- this.formModel = {};
- for (let i = 0; i < this.grids.length; i++) {
- const grid = this.grids[i];
- //获取报销详情前的基本信息数据
- if (this.isNotEmpty(grid.name)) {
- // 切掉数组中从当前索引开始的所有元素
- this.gridsTest = this.grids.slice(0, i);
- break;
- }
- }
- this.gridsTest.forEach(grid => {
- grid.columns.forEach(col => {
- col.list.forEach(field => {
- this.$set(this.formModel, field.model, field.options.defaultValue || '');
- });
- });
- });
- this.getReimbursementDetails();
- this.getInvoiceDetails();
- },
- //报销详情数据处理
- getReimbursementDetails() {
- this.formModelDetail = [];
- let startIndex = -1;
- let endIndex = -1;
- // 找到 "报销详情" 和 "专用发票信息" 的索引
- for (let i = 0; i < this.grids.length; i++) {
- const grid = this.grids[i];
- if (grid.name === "报销详情") {
- startIndex = i;
- }
- if (grid.name === "专用发票信息") {
- endIndex = i;
- break;
- }
- }
- // 确保找到的索引是有效的,并且 startIndex 在 endIndex 之前
- if (startIndex !== -1 && endIndex !== -1 && startIndex < endIndex) {
- // 提取 startIndex 和 endIndex 之间的数据(不包括 "报销详情" 和 "专用发票信息" 本身)
- this.gridsDetail = this.grids.slice(startIndex + 1, endIndex);
- // 初始化 formModelDetail
- const defaultValueList = this.gridsDetail[0].options.defaultValue || [];
- defaultValueList.forEach((defaultValue, index_experience) => {
- const data = {};
- this.gridsDetail.forEach(grid => {
- grid.tableColumns.forEach(column => {
- if (defaultValue.hasOwnProperty(column.model)) {
- this.$set(data, column.model, defaultValue[column.model] || '');
- }
- });
- });
- this.$set(this.formModelDetail, index_experience, data);
- });
- } else {
- // 如果没有找到有效的索引范围,清空 gridsDetail
- this.gridsDetail = [];
- }
- },
- // 发票详情数据处理
- getInvoiceDetails() {
- this.invoiceFormModelDetail = [];
- let endIndex = -1;
- // 找到 "专用发票信息" 的索引
- for (let i = 0; i < this.grids.length; i++) {
- const grid = this.grids[i];
- if (grid.name === "专用发票信息") {
- endIndex = i;
- break;
- }
- }
- // 确保找到的索引是有效的,并且 startIndex 在 endIndex 之前
- if (endIndex !== -1 && endIndex < this.grids.length ) {
- // 提取 startIndex 和 endIndex 之间的数据(不包括 "报销详情" 和 "专用发票信息" 本身)
- this.gridsInvoice = this.grids.slice(endIndex + 1, this.grids.length);
- // 初始化 invoiceFormModelDetail
- const defaultValueList = this.gridsInvoice[0].options.defaultValue || [];
- defaultValueList.forEach((defaultValue, invoice_index) => {
- const data = {};
- this.gridsInvoice.forEach(grid => {
- grid.tableColumns.forEach(column => {
- if (defaultValue.hasOwnProperty(column.model)) {
- this.$set(data, column.model, defaultValue[column.model] || '');
- }
- });
- });
- this.$set(this.invoiceFormModelDetail, invoice_index, data);
- });
- } else {
- // 如果没有找到有效的索引范围,清空 gridsInvoice
- this.gridsInvoice = [];
- }
- },
- isEmpty(value) {
- let result = false;
- if (value == null || value == undefined) {
- result = true;
- }
- if (typeof value == 'string' && (value.replace(/\s+/g, "") == "" || value == "")) {
- result = true;
- }
- if (typeof value == "object" && value instanceof Array && value.length === 0) {
- result = true;
- }
- return result;
- },
- isNotEmpty(value) {
- return !this.isEmpty(value);
- },
- shouldShowFile(file) {
- if (this.files && this.files.length > 0) {
- // 返回一个布尔值,确定是否显示上传成功后的文件
- return this.showFileList[this.files.indexOf(file)];
- }
- return false; // 默认返回 false 或者其他适当的
- },
- async handleFileClick(file) {
- await this.ossService.getTemporaryUrl(file.url).then((data) => {
- file.lsUrl = data
- })
- if (this.isImage(file.name)) {
- // 如果是图片文件,则执行放大显示图片的逻辑
- this.handleImageClick(file.lsUrl);
- } else {
- // window.open(file.lsUrl, '_blank')
- window.location.href = file.lsUrl
- // 如果不是图片文件,则执行其他操作,比如下载文件等
- }
- },
- // 判断文件是否是图片类型
- isImage(fileName) {
- const ext = fileName.toLowerCase().split('.').pop(); // 获取文件的后缀名
- return ['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(ext); // 判断后缀名是否是图片类型
- },
- handleImageClick(url) {
- let urls = [url]
- // 大图预览
- uni.previewImage({
- current: url,
- urls: urls,
- })
- // 在点击图片时执行放大显示的逻辑
- // this.$alert(`<img src="${file.lsUrl}" style="max-width: 100%; max-height: 100%;" />`, '图片详情', {
- // dangerouslyUseHTMLString: true,
- // customClass: 'custom-alert'
- // });
- },
- handleDelete(file) {
- // 处理删除文件的逻辑
- // 从文件列表中移除文件
- const index = this.files.indexOf(file);
- if (index !== -1) {
- this.files.splice(index, 1);
- this.showFileList.splice(index, 1); // 从showFileList中移除对应的元素
- }
- },
- }
- };
- </script>
- <style scoped>
- .form-grid {
- margin-bottom: 10px; /* 减少外边距 */
- }
- .form-column {
- display: flex;
- flex-direction: column;
- margin-bottom: 10px; /* 减少外边距 */
- }
- .form-field {
- margin-bottom: 10px; /* 减少外边距 */
- }
- .form-item {
- display: flex;
- flex-direction: column;
- }
- .input-field, .textarea-field {
- width: 100%;
- height: 30px;
- border: 1px solid #ccc;
- border-radius: 4px;
- }
- .textarea-field {
- height: 60px;
- }
- /* 禁用状态样式 */
- .input-disabled {
- background-color: #f5f5f5;
- border-color: #dcdcdc;
- cursor: not-allowed;
- }
- .textarea-disabled {
- background-color: #f5f5f5;
- border-color: #dcdcdc;
- cursor: not-allowed;
- }
- /* 解决父级容器的内边距问题 */
- .upload-demo {
- margin-top: 10px; /* 增加间距 */
- }
- </style>
|