123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- <template>
- <div class="_fc-table-form" :class="{'_fc-disabled': disabled}">
- <component :is="Form" :option="options" :rule="rule" :extendOption="true"
- :disabled="disabled"
- @change="formChange"
- v-model:api="fapi"
- @emit-event="$emit"></component>
- <el-button link type="primary" class="fc-clock" v-if="!max || max > this.trs.length"
- @click="addRaw(true)"><i class="fc-icon icon-add-circle" style="font-weight: 700;"></i>
- {{ formCreateInject.t('add') || '添加' }}
- </el-button>
- </div>
- </template>
- <script>
- import {markRaw, reactive} from 'vue';
- export default {
- name: 'TableForm',
- emits: ['change', 'add', 'delete', 'update:modelValue'],
- props: {
- formCreateInject: Object,
- modelValue: {
- type: Array,
- default: () => [],
- },
- columns: {
- type: Array,
- required: true,
- default: () => []
- },
- filterEmptyColumn: {
- type: Boolean,
- default: true,
- },
- options: {
- type: Object,
- default: () => reactive(({
- submitBtn: false,
- resetBtn: false,
- }))
- },
- max: Number,
- disabled: Boolean,
- },
- watch: {
- modelValue: {
- handler() {
- this.updateTable()
- },
- deep: true
- },
- 'formCreateInject.preview': function (n) {
- this.emptyRule.children[0].props.colspan = this.columns.length + (n ? 1 : 2);
- },
- },
- data() {
- return {
- rule: [],
- trs: [],
- fapi: {},
- Form: markRaw(this.formCreateInject.form.$form()),
- copyTrs: '',
- oldValue: '',
- emptyRule: {
- type: 'tr',
- _isEmpty: true,
- native: true,
- subRule: true,
- children: [
- {
- type: 'td',
- style: {
- textAlign: 'center',
- },
- native: true,
- subRule: true,
- props: {
- colspan: this.columns.length + (this.formCreateInject.preview ? 1 : 2),
- },
- children: [this.formCreateInject.t('dataEmpty') || '暂无数据']
- }
- ]
- },
- };
- },
- methods: {
- formChange() {
- this.updateValue();
- },
- updateValue() {
- const value = this.trs.map((tr, idx) => {
- return {
- ...(this.modelValue[idx] || {}),
- ...this.fapi.getChildrenFormData(tr)
- }
- }).filter(v => {
- if (!this.filterEmptyColumn) {
- return true;
- }
- if (v === undefined || v === null) {
- return false;
- }
- let flag = false;
- Object.keys(v).forEach(k => {
- flag = flag || (v[k] !== undefined && v[k] !== '' && v[k] !== null)
- })
- return flag;
- });
- const str = JSON.stringify(value);
- if (str !== this.oldValue) {
- this.oldValue = str;
- this.$emit('update:modelValue', value);
- this.$emit('change', value);
- }
- },
- setRawData(idx, formData) {
- const raw = this.trs[idx];
- this.fapi.setChildrenFormData(raw, formData, true);
- },
- updateTable() {
- const str = JSON.stringify(this.modelValue);
- if (this.oldValue === str) {
- return;
- }
- this.oldValue = str;
- this.trs = this.trs.splice(0, this.modelValue.length);
- if (!this.modelValue.length) {
- this.addEmpty();
- } else {
- this.clearEmpty();
- }
- this.modelValue.forEach((data, idx) => {
- if (!this.trs[idx]) {
- this.addRaw();
- }
- this.setRawData(idx, data || {});
- });
- this.rule[0].children[1].children = this.trs;
- },
- addEmpty() {
- if (this.trs.length) {
- this.trs.splice(0, this.trs.length);
- }
- this.trs.push(this.emptyRule);
- },
- clearEmpty() {
- if (this.trs[0] && this.trs[0]._isEmpty) {
- this.trs.splice(0, 1);
- }
- },
- delRaw(idx) {
- if (this.disabled) {
- return;
- }
- this.trs.splice(idx, 1);
- this.updateValue();
- if (this.trs.length) {
- this.trs.forEach(tr => this.updateRaw(tr));
- } else {
- this.addEmpty();
- }
- this.$emit('delete', idx);
- },
- addRaw(flag) {
- if (flag && this.disabled) {
- return;
- }
- const tr = this.formCreateInject.form.parseJson(this.copyTrs)[0];
- if (this.trs.length === 1 && this.trs[0]._isEmpty) {
- this.trs.splice(0, 1);
- }
- this.trs.push(tr);
- this.updateRaw(tr);
- if (flag) {
- this.$emit('add', this.trs.length);
- this.updateValue();
- }
- },
- updateRaw(tr) {
- const idx = this.trs.indexOf(tr);
- tr.children[0].props.innerText = idx + 1;
- tr.children[tr.children.length - 1].children[0].props.onClick = () => {
- this.delRaw(idx);
- };
- },
- loadRule() {
- const header = [{
- type: 'th',
- native: true,
- class: '_fc-tf-head-idx',
- props: {
- innerText: '#'
- }
- }];
- let body = [{
- type: 'td',
- class: '_fc-tf-idx',
- native: true,
- props: {
- innerText: '0'
- }
- }];
- this.columns.forEach((column) => {
- header.push({
- type: 'th',
- native: true,
- style: column.style,
- class: column.required ? '_fc-tf-head-required' : '',
- props: {
- innerText: column.label || ''
- }
- });
- body.push({
- type: 'td',
- native: true,
- children: [...(column.rule || [])]
- });
- });
- header.push({
- type: 'th',
- native: true,
- class: '_fc-tf-edit fc-clock',
- props: {
- innerText: this.formCreateInject.t('operation') || '操作'
- }
- });
- body.push({
- type: 'td',
- native: true,
- class: '_fc-tf-btn fc-clock',
- children: [
- {
- type: 'i',
- native: true,
- class: 'fc-icon icon-delete',
- props: {},
- }
- ],
- });
- this.copyTrs = this.formCreateInject.form.toJson([
- {
- type: 'tr',
- native: true,
- subRule: true,
- children: body
- }
- ]);
- this.rule = [
- {
- type: 'table',
- native: true,
- class: '_fc-tf-table',
- props: {
- border: '1',
- cellspacing: '0',
- cellpadding: '0',
- },
- children: [
- {
- type: 'thead',
- native: true,
- children: [
- {
- type: 'tr',
- native: true,
- children: header
- }
- ]
- },
- {
- type: 'tbody',
- native: true,
- children: this.trs
- }
- ]
- }
- ]
- },
- },
- created() {
- this.loadRule();
- },
- mounted() {
- this.updateTable();
- }
- };
- </script>
- <style>
- ._fc-table-form {
- overflow: auto;
- color: #666666;
- }
- ._fc-table-form .form-create .el-form-item {
- margin-bottom: 1px;
- }
- ._fc-table-form .form-create .el-form-item.is-error {
- margin-bottom: 22px;
- }
- ._fc-table-form .el-form-item__label, ._fc-table-form .van-field__label {
- display: none !important;
- }
- ._fc-table-form .el-form-item__content {
- display: flex;
- margin-left: 0px !important;
- width: 100% !important;
- }
- ._fc-tf-head-idx, ._fc-tf-idx {
- width: 40px;
- min-width: 40px;
- font-weight: 500;
- text-align: center;
- }
- ._fc-tf-edit, ._fc-tf-btn {
- width: 70px;
- min-width: 70px;
- text-align: center;
- }
- ._fc-tf-btn .fc-icon {
- cursor: pointer;
- }
- ._fc-table-form._fc-disabled ._fc-tf-btn .fc-icon, ._fc-table-form._fc-disabled > .el-button {
- cursor: not-allowed;
- }
- ._fc-tf-table {
- width: 100%;
- height: 100%;
- overflow: hidden;
- table-layout: fixed;
- border: 1px solid #EBEEF5;
- border-bottom: 0 none;
- }
- ._fc-table-form ._fc-tf-table > thead > tr > th {
- border: 0 none;
- border-bottom: 1px solid #EBEEF5;
- height: 40px;
- font-weight: 500;
- }
- ._fc-table-form ._fc-tf-table > thead > tr > th + th {
- border-left: 1px solid #EBEEF5;
- }
- ._fc-table-form tr {
- min-height: 50px;
- }
- ._fc-table-form ._fc-read-view {
- text-align: center;
- width: 100%;
- }
- ._fc-table-form td {
- padding: 5px;
- min-height: 50px;
- min-width: 80px;
- position: relative;
- box-sizing: border-box;
- overflow-wrap: break-word;
- /*white-space: nowrap;*/
- overflow: hidden;
- border: 0 none;
- border-bottom: 1px solid #EBEEF5;
- }
- ._fc-table-form td + td {
- border-left: 1px solid #EBEEF5;
- }
- ._fc-tf-table .el-input-number, ._fc-tf-table .el-select, ._fc-tf-table .el-slider, ._fc-tf-table .el-cascader, ._fc-tf-table .el-date-editor {
- width: 100%;
- }
- ._fc-tf-head-required:before {
- content: '*';
- color: #f56c6c;
- margin-right: 4px;
- }
- </style>
|