projects/mes-test #133
@@ -76,6 +76,7 @@
 | 
			
		||||
						class="upload-area"
 | 
			
		||||
						:class="uploadOpen ? '' : 'height-48'"
 | 
			
		||||
						ref="uploadArea"
 | 
			
		||||
						:key="col.prop"
 | 
			
		||||
						v-if="col.upload">
 | 
			
		||||
						<span class="close-icon" :class="uploadOpen ? 'open' : ''">
 | 
			
		||||
							<el-button
 | 
			
		||||
@@ -87,13 +88,18 @@
 | 
			
		||||
						<el-upload
 | 
			
		||||
							class="upload-in-dialog"
 | 
			
		||||
							v-if="col.upload"
 | 
			
		||||
							:key="col.prop + '__el-upload'"
 | 
			
		||||
							:action="uploadUrl"
 | 
			
		||||
							:headers="uploadHeaders"
 | 
			
		||||
							:show-file-list="false"
 | 
			
		||||
							icon="el-icon-upload2"
 | 
			
		||||
							:disabled="disabled"
 | 
			
		||||
							:before-upload="beforeUpload"
 | 
			
		||||
							:on-success="handleUploadSuccess"
 | 
			
		||||
							:on-success="
 | 
			
		||||
								(response, file, fileList) => {
 | 
			
		||||
									handleUploadSuccess(response, file, col.prop);
 | 
			
		||||
								}
 | 
			
		||||
							"
 | 
			
		||||
							v-bind="col.bind">
 | 
			
		||||
							<el-button size="mini" :disabled="col.bind?.disabled || false">
 | 
			
		||||
								<svg-icon
 | 
			
		||||
@@ -108,10 +114,10 @@
 | 
			
		||||
 | 
			
		||||
						<uploadedFile
 | 
			
		||||
							class="file"
 | 
			
		||||
							v-for="file in form[col.prop] || []"
 | 
			
		||||
							v-for="file in form[col.prop]"
 | 
			
		||||
							:file="file"
 | 
			
		||||
							:key="file.fileUrl"
 | 
			
		||||
							@delete="!disabled && handleDeleteFile(file)" />
 | 
			
		||||
							@delete="!disabled && handleDeleteFile(file, col.prop)" />
 | 
			
		||||
					</div>
 | 
			
		||||
				</el-form-item>
 | 
			
		||||
			</el-col>
 | 
			
		||||
@@ -152,12 +158,30 @@ const uploadedFile = {
 | 
			
		||||
		handleDelete() {
 | 
			
		||||
			this.$emit('delete', this.file);
 | 
			
		||||
		},
 | 
			
		||||
		async handleDownload() {
 | 
			
		||||
			const data = await this.$axios({
 | 
			
		||||
				url: this.file.fileUrl,
 | 
			
		||||
				method: 'get',
 | 
			
		||||
				responseType: 'blob',
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			await this.$message.success('开始下载');
 | 
			
		||||
			// create download link
 | 
			
		||||
			const url = window.URL.createObjectURL(data);
 | 
			
		||||
			const link = document.createElement('a');
 | 
			
		||||
			link.href = url;
 | 
			
		||||
			link.download = this.file.fileName;
 | 
			
		||||
			document.body.appendChild(link);
 | 
			
		||||
			link.click();
 | 
			
		||||
			document.body.removeChild(link);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {},
 | 
			
		||||
	render: function (h) {
 | 
			
		||||
		return (
 | 
			
		||||
			<div
 | 
			
		||||
				title={this.file.fileName}
 | 
			
		||||
				onClick={this.handleDownload}
 | 
			
		||||
				style={{
 | 
			
		||||
					background: `url(${tupleImg}) no-repeat`,
 | 
			
		||||
					backgroundSize: '14px',
 | 
			
		||||
@@ -205,7 +229,7 @@ export default {
 | 
			
		||||
			default: false,
 | 
			
		||||
		},
 | 
			
		||||
		hasFiles: {
 | 
			
		||||
			type: Boolean,
 | 
			
		||||
			type: Boolean | Array,
 | 
			
		||||
			default: false,
 | 
			
		||||
		},
 | 
			
		||||
		labelPosition: {
 | 
			
		||||
@@ -251,7 +275,13 @@ export default {
 | 
			
		||||
			handler(val) {
 | 
			
		||||
				this.form = JSON.parse(JSON.stringify(val));
 | 
			
		||||
				if (this.hasFiles) {
 | 
			
		||||
					this.form.files = this.form.files ?? [];
 | 
			
		||||
					if (typeof this.hasFiles == 'boolean' && this.hasFiles) {
 | 
			
		||||
						this.form.files = this.form.files ?? [];
 | 
			
		||||
					} else if (Array.isArray(this.hasFiles)) {
 | 
			
		||||
						this.hasFiles.forEach((prop) => {
 | 
			
		||||
							this.form[prop] = this.form[prop] ?? [];
 | 
			
		||||
						});
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
@@ -348,7 +378,7 @@ export default {
 | 
			
		||||
									// 处理输入框数据
 | 
			
		||||
									this.form[opt.prop] = response.data;
 | 
			
		||||
									// 更新下外部的 dataForm,防止code字段有数据也报空的bug
 | 
			
		||||
									this.$emit('update', this.form)
 | 
			
		||||
									this.$emit('update', this.form);
 | 
			
		||||
								}
 | 
			
		||||
							});
 | 
			
		||||
						}
 | 
			
		||||
@@ -377,11 +407,12 @@ export default {
 | 
			
		||||
		// 上传成功的特殊处理
 | 
			
		||||
		beforeUpload() {},
 | 
			
		||||
		// 上传前的验证规则可通过 bind 属性传入
 | 
			
		||||
		handleUploadSuccess(response, file, fileList) {
 | 
			
		||||
			this.form.files.push({
 | 
			
		||||
		handleUploadSuccess(response, file, prop) {
 | 
			
		||||
			console.log('[handleUploadSuccess]', response, file, prop);
 | 
			
		||||
			this.form[prop].push({
 | 
			
		||||
				fileName: file.name,
 | 
			
		||||
				fileUrl: response.data,
 | 
			
		||||
				fileType: 2,
 | 
			
		||||
				fileType: prop == 'files' ? 2 : 1,
 | 
			
		||||
			});
 | 
			
		||||
			this.$modal.msgSuccess('上传成功');
 | 
			
		||||
			this.$emit('update', this.form);
 | 
			
		||||
@@ -395,8 +426,8 @@ export default {
 | 
			
		||||
			this.uploadOpen = !this.uploadOpen;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		handleDeleteFile(file) {
 | 
			
		||||
			this.form.files = this.form.files.filter(
 | 
			
		||||
		handleDeleteFile(file, prop) {
 | 
			
		||||
			this.form[prop] = this.form[prop].filter(
 | 
			
		||||
				(item) => item.fileUrl != file.fileUrl
 | 
			
		||||
			);
 | 
			
		||||
			this.$emit('update', this.form);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,978 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <el-dialog class="dialog-with-menu" :visible="dialogVisible" :destroy-on-close="false" @close="handleClose"
 | 
			
		||||
    :close-on-click-modal="configs.clickModalToClose ?? true">
 | 
			
		||||
    <!-- title  -->
 | 
			
		||||
    <div slot="title" class="dialog-title">
 | 
			
		||||
      <h1 class="">
 | 
			
		||||
        {{ detailMode ? "查看详情" : dataForm.id ? "编辑" : "新增" }}
 | 
			
		||||
      </h1>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="dialog-body__inner relative">
 | 
			
		||||
      <!-- v-if="dataForm.id && !detailMode && /属性|详情/.test(activeMenu) && $hasPermission()" -->
 | 
			
		||||
      <el-button v-if="configs.allowAdd ?? (dataForm.id && !detailMode && /属性|详情|参数/.test(activeMenu))" plain
 | 
			
		||||
        type="primary" size="small" class="at-right-top" style="margin-bottom: 16px" @click="handleAddParam()">+
 | 
			
		||||
        添加</el-button>
 | 
			
		||||
      <template v-if="dataForm.id && !detailMode && /附件/.test(activeMenu)">
 | 
			
		||||
        <el-upload style="position: absolute; width: 100%; height: 0" name="files" :action="uploadUrl"
 | 
			
		||||
          :show-file-list="false" :headers="uploadHeaders" :on-success="handleUploadSuccess"
 | 
			
		||||
          :before-upload="handleUploadCheck">
 | 
			
		||||
          <el-button plain type="primary" size="small" class="at-right-top" style=""> <i class="el-icon-upload"></i> 上传
 | 
			
		||||
          </el-button>
 | 
			
		||||
        </el-upload>
 | 
			
		||||
      </template>
 | 
			
		||||
 | 
			
		||||
      <!-- menu  -->
 | 
			
		||||
      <el-tabs v-model="activeMenu" type="card" @tab-click="handleTabClick">
 | 
			
		||||
        <!-- <el-tab-pane v-for="(tab, index) in configs.menu" :key="index" :label="tab.name" :name="tab.name"> -->
 | 
			
		||||
        <el-tab-pane v-for="(tab, index) in actualMenus" :key="index" :name="tab.name">
 | 
			
		||||
          <span class="slot" slot="label">
 | 
			
		||||
            <i :class="{
 | 
			
		||||
              'el-icon-edit': tab.key === 'info',
 | 
			
		||||
              'el-icon-s-data': tab.key === 'attr',
 | 
			
		||||
              'el-icon-folder-opened': tab.key === 'attachment',
 | 
			
		||||
            }"></i>
 | 
			
		||||
            {{ tab.name }}
 | 
			
		||||
          </span>
 | 
			
		||||
 | 
			
		||||
          <!-- 表单标签页 -->
 | 
			
		||||
          <div v-if="tab.key === 'info'">
 | 
			
		||||
            <!-- form  -->
 | 
			
		||||
            <el-form ref="dataForm" :model="dataForm" v-loading="loadingStatus">
 | 
			
		||||
              <el-row v-for="(row, rowIndex) in configs.form.rows" :key="'row_' + rowIndex" :gutter="20">
 | 
			
		||||
                <el-col v-for="(col, colIndex) in row" :key="colIndex" :span="24 / row.length">
 | 
			
		||||
                  <el-form-item :label="col.label" :prop="col.prop" :rules="col.rules || null"
 | 
			
		||||
                    v-show="!col.forceDisabled || (col.forceDisabled && dataForm.id)">
 | 
			
		||||
                    <div v-if="col.forceDisabled && dataForm.id" class="force-disabled">
 | 
			
		||||
                      <el-tag :key="col.key" :type="col.type">{{ dataForm[col.prop] || "-" }}</el-tag>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <el-input v-if="col.input" v-model="dataForm[col.prop]" clearable
 | 
			
		||||
                      :disabled="disableCondition(col.prop)" v-bind="col.elparams" />
 | 
			
		||||
                    <el-cascader v-if="col.cascader" v-model="dataForm[col.prop]" :options="col.options"
 | 
			
		||||
                      :disabled="detailMode" v-bind="col.elparams"></el-cascader>
 | 
			
		||||
                    <el-select v-if="col.select" v-model="dataForm[col.prop]" clearable
 | 
			
		||||
                      :disabled="disableCondition(col.prop)" v-bind="col.elparams"
 | 
			
		||||
                      @change="handleSelectChange(col, $event)">
 | 
			
		||||
                      <el-option v-for="(opt, optIdx) in col.options" :key="'option_' + optIdx" :label="opt.label"
 | 
			
		||||
                        :value="opt.value" />
 | 
			
		||||
                    </el-select>
 | 
			
		||||
                    <el-switch v-if="col.switch" v-model="dataForm[col.prop]" :active-value="1" :inactive-value="0"
 | 
			
		||||
                      @change="handleSwitchChange" :disabled="disableCondition(col.prop)" />
 | 
			
		||||
                    <el-input v-if="col.textarea" type="textarea" v-model="dataForm[col.prop]"
 | 
			
		||||
                      :disabled="disableCondition(col.prop)" v-bind="col.elparams" />
 | 
			
		||||
                    <quillEditor v-if="col.richInput" ref="quill-editor" v-model="dataForm[col.prop]"
 | 
			
		||||
                      :options="col.quillConfig ?? defaultQuillConfig" style="margin-top: 42px"
 | 
			
		||||
                      :disabled="disableCondition(col.prop)" />
 | 
			
		||||
 | 
			
		||||
                    <div class="" v-if="col.component" style="margin: 42px 0 0">
 | 
			
		||||
                      <!-- 下面这个 component 几乎是为 富文本 quill 定制的了... TODO:后续可能会根据业务需求创建新的版本  -->
 | 
			
		||||
                      <component :is="col.component" :key="'component_' + col.prop"
 | 
			
		||||
                        @update:modelValue="handleComponentModelUpdate(col.prop, $event)" :modelValue="dataForm[col.prop]"
 | 
			
		||||
                        :mode="detailMode ? 'detail' : dataForm.id ? 'edit' : 'create'" />
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <!-- add more...  -->
 | 
			
		||||
                  </el-form-item>
 | 
			
		||||
                </el-col>
 | 
			
		||||
              </el-row>
 | 
			
		||||
            </el-form>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <!-- 表格标签页 -->
 | 
			
		||||
          <div v-if="dataForm.id && tab.key === 'attr'" key="attr-list">
 | 
			
		||||
            <BaseListTable :table-config="null" :column-config="filteredTableProps" :table-data="subList"
 | 
			
		||||
              @operate-event="handleTableRowOperate" :current-page="attrPage" :current-size="attrSize"
 | 
			
		||||
              :refresh-layout-key="Math.random()" v-loading="loadingStatus" />
 | 
			
		||||
            <!-- paginator  -->
 | 
			
		||||
            <el-pagination class="" style="text-align: left" background @size-change="handleSizeChange"
 | 
			
		||||
              @current-change="handlePageChange" :current-page.sync="attrPage" :page-sizes="[5, 10, 20]"
 | 
			
		||||
              :page-size="attrSize" :total="attrTotal" layout="total, sizes, prev, next"></el-pagination>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <!-- 附件标签页 -->
 | 
			
		||||
          <div v-if="dataForm.id && tab.key === 'attachment'" key="attachment">
 | 
			
		||||
            <div class="upload-tips" style="font-size: 0.8em; margin-bottom: 12px">文件大小不要超过 2MB</div>
 | 
			
		||||
            <!-- 附件列表 -->
 | 
			
		||||
            <div class="" v-loading="loadingStatus">
 | 
			
		||||
              <ul class="file-list">
 | 
			
		||||
                <li v-for="(file, index) in fileList" :key="index">
 | 
			
		||||
                  <span class="file-name">{{ file.name }}</span>
 | 
			
		||||
                  <span class="file-operations">
 | 
			
		||||
                    <span class="file-icon preview" @click="handleFileClick('view', file)">
 | 
			
		||||
                      <i class="el-icon-view" style="cursor: pointer"></i>
 | 
			
		||||
                    </span>
 | 
			
		||||
                    <span class="file-icon download" @click="handleFileClick('download', file)">
 | 
			
		||||
                      <i class="el-icon-download" style="color: #0b58ff; cursor: pointer"></i>
 | 
			
		||||
                    </span>
 | 
			
		||||
                    <span class="file-icon delete" @click="handleFileClick('delete', file)">
 | 
			
		||||
                      <i class="el-icon-delete" style="color: red; cursor: pointer"></i>
 | 
			
		||||
                    </span>
 | 
			
		||||
                  </span>
 | 
			
		||||
                </li>
 | 
			
		||||
              </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
            <!-- img preview dialog  -->
 | 
			
		||||
            <el-dialog key="image-preview-dialog" class="image-preview-dialog" :visible.sync="imgPreviewDialogVisible"
 | 
			
		||||
              :append-to-body="true">
 | 
			
		||||
              <div class="img-container">
 | 
			
		||||
                <img width="100%" :src="currentImgUrl" alt="" />
 | 
			
		||||
              </div>
 | 
			
		||||
            </el-dialog>
 | 
			
		||||
          </div>
 | 
			
		||||
        </el-tab-pane>
 | 
			
		||||
      </el-tabs>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- sub dialog  -->
 | 
			
		||||
    <small-dialog :append-to-body="true" v-if="showSubDialog" ref="subDialog" :url="urls.subase"
 | 
			
		||||
      :configs="configs.subDialog" :related-id="dataForm.id" @refreshDataList="getSubList"></small-dialog>
 | 
			
		||||
 | 
			
		||||
    <!-- footer  -->
 | 
			
		||||
    <div slot="footer">
 | 
			
		||||
      <template v-for="(operate, index) in configs.form.operations">
 | 
			
		||||
        <el-button v-if="showButton(operate)" :key="'operation_' + index" :type="operate.type"
 | 
			
		||||
          @click="handleBtnClick(operate)"
 | 
			
		||||
          :loading="(operate.name === 'add' || operate.name === 'update') && btnLoading">{{ operate.label }}</el-button>
 | 
			
		||||
      </template>
 | 
			
		||||
      <el-button @click="handleBtnClick({ name: 'cancel' })">取消</el-button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </el-dialog>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { pick as __pick } from "@/utils/filters";
 | 
			
		||||
import SmallDialog from "@/components/SmallDialog.vue";
 | 
			
		||||
import BaseListTable from "@/components/BaseListTable.vue";
 | 
			
		||||
import Cookies from "js-cookie";
 | 
			
		||||
import "quill/dist/quill.core.css";
 | 
			
		||||
import "quill/dist/quill.snow.css";
 | 
			
		||||
import "quill/dist/quill.bubble.css";
 | 
			
		||||
 | 
			
		||||
import { quillEditor } from "vue-quill-editor";
 | 
			
		||||
 | 
			
		||||
function reConstructTreeData(listObj) {
 | 
			
		||||
  const entry = [];
 | 
			
		||||
  Object.keys(listObj).map((key) => {
 | 
			
		||||
    const currentNode = listObj[key];
 | 
			
		||||
    currentNode.label = currentNode.name;
 | 
			
		||||
    currentNode.value = currentNode.id;
 | 
			
		||||
    if (currentNode.parentId === "0") {
 | 
			
		||||
      entry.push(listObj[key]);
 | 
			
		||||
      return; // return { label: currentNode.name, value: currentNode.id, children: currentNode.children ?? [] };
 | 
			
		||||
    }
 | 
			
		||||
    const parentNode = listObj[currentNode.parentId];
 | 
			
		||||
    if (!parentNode.children) {
 | 
			
		||||
      parentNode.children = [];
 | 
			
		||||
    }
 | 
			
		||||
    parentNode.children.push(currentNode);
 | 
			
		||||
  });
 | 
			
		||||
  return entry;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "DialogWithMenu",
 | 
			
		||||
  components: { SmallDialog, BaseListTable, quillEditor },
 | 
			
		||||
  props: {
 | 
			
		||||
    configs: {
 | 
			
		||||
      type: Object,
 | 
			
		||||
      default: () => ({}),
 | 
			
		||||
    },
 | 
			
		||||
    dialogVisible: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      default: false,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  inject: ["urls"],
 | 
			
		||||
  data() {
 | 
			
		||||
    const dataForm = {};
 | 
			
		||||
    const autoDisabledQueue = [];
 | 
			
		||||
    const watingToRefreshQueue = [];
 | 
			
		||||
    const cached = {}
 | 
			
		||||
 | 
			
		||||
    this.configs.form.rows.forEach((row) => {
 | 
			
		||||
      row.forEach((col) => {
 | 
			
		||||
        if (col.upload) dataForm[col.prop] = col.default ?? [];
 | 
			
		||||
        else dataForm[col.prop] = col.default ?? null;
 | 
			
		||||
 | 
			
		||||
        if (col.autoDisabled) autoDisabledQueue.push(col.prop);
 | 
			
		||||
        if (!!col.refreshOptionsAfterConfirm) watingToRefreshQueue.push(col);
 | 
			
		||||
 | 
			
		||||
        if (col.fetchData)
 | 
			
		||||
          col.fetchData().then(({ data: res }) => {
 | 
			
		||||
            console.log("[Fetch Data]", "list" in res.data, res.data, res.data.list);
 | 
			
		||||
            if (res.code === 0) {
 | 
			
		||||
              if (col.cacheFetchedData) {
 | 
			
		||||
                // cache fetched data
 | 
			
		||||
                cached[col.prop] = 'list' in res.data ? res.data.list : (Array.isArray(res.data) ? res.data : [])
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              if (!col.options || !col.options.length) {
 | 
			
		||||
                this.$set(
 | 
			
		||||
                  col,
 | 
			
		||||
                  "options",
 | 
			
		||||
                  "list" in res.data
 | 
			
		||||
                    ? res.data.list.map((i) => ({
 | 
			
		||||
                      label: col.optionLabel ? i[col.optionLabel] : i.name,
 | 
			
		||||
                      value: col.optionValue ? i[col.optionValue] : i.id,
 | 
			
		||||
                    }))
 | 
			
		||||
                    : res.data.map((i) => ({
 | 
			
		||||
                      label: col.optionLabel ? i[col.optionLabel] : i.name,
 | 
			
		||||
                      value: col.optionValue ? i[col.optionValue] : i.id,
 | 
			
		||||
                    }))
 | 
			
		||||
                );
 | 
			
		||||
              }
 | 
			
		||||
              // col.options = res.data.list;
 | 
			
		||||
              else if (col.options.length) {
 | 
			
		||||
                "list" in res.data ? res.data.list.unshift(...col.options) : res.data.unshift(...col.options);
 | 
			
		||||
                this.$set(
 | 
			
		||||
                  col,
 | 
			
		||||
                  "options",
 | 
			
		||||
                  "list" in res.data
 | 
			
		||||
                    ? res.data.list.map((i) => ({
 | 
			
		||||
                      label: col.optionLabel ? i[col.optionLabel] : i.name,
 | 
			
		||||
                      value: col.optionValue ? i[col.optionValue] : i.id,
 | 
			
		||||
                    }))
 | 
			
		||||
                    : res.data.map((i) => ({
 | 
			
		||||
                      label: col.optionLabel ? i[col.optionLabel] : i.name,
 | 
			
		||||
                      value: col.optionValue ? i[col.optionValue] : i.id,
 | 
			
		||||
                    }))
 | 
			
		||||
                );
 | 
			
		||||
              }
 | 
			
		||||
            } else {
 | 
			
		||||
              col.options.splice(0);
 | 
			
		||||
            }
 | 
			
		||||
            // dataForm[col.prop] = col.default ?? null; // not perfect!
 | 
			
		||||
          });
 | 
			
		||||
        else if (col.fetchTreeData) {
 | 
			
		||||
          // 获取设备类型时触发的,用于前端构建属性结构,约定,parentId 为0时是顶级节点
 | 
			
		||||
          col.fetchTreeData().then(({ data: res }) => {
 | 
			
		||||
            console.log("[Fetch Tree Data]", res.data);
 | 
			
		||||
            if (res.code === 0) {
 | 
			
		||||
              // 先把数据先重构成一个对象
 | 
			
		||||
              const obj = {};
 | 
			
		||||
 | 
			
		||||
              if ("list" in res.data) {
 | 
			
		||||
                res.data.list.map((item) => {
 | 
			
		||||
                  obj[item.id] = item;
 | 
			
		||||
                });
 | 
			
		||||
              } else if (Array.isArray(res.data)) {
 | 
			
		||||
                res.data.map((item) => {
 | 
			
		||||
                  obj[item.id] = item;
 | 
			
		||||
                });
 | 
			
		||||
              }
 | 
			
		||||
              // 再过滤这个对象
 | 
			
		||||
              let filteredList = reConstructTreeData(obj);
 | 
			
		||||
              console.log("** filteredList **", filteredList);
 | 
			
		||||
              // 最后设置 options
 | 
			
		||||
              this.$set(col, "options", filteredList);
 | 
			
		||||
            } else {
 | 
			
		||||
              col.options.splice(0);
 | 
			
		||||
              this.$message.error(res.msg);
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      // configs,
 | 
			
		||||
      btnLoading: false,
 | 
			
		||||
      loadingStatus: false,
 | 
			
		||||
      activeMenu: this.configs.menu[0].name,
 | 
			
		||||
      dataForm,
 | 
			
		||||
      detailMode: false,
 | 
			
		||||
      autoDisabledQueue,
 | 
			
		||||
      watingToRefreshQueue,
 | 
			
		||||
      cached,
 | 
			
		||||
      showBaseDialog: false,
 | 
			
		||||
      baseDialogConfig: null,
 | 
			
		||||
      subList: [],
 | 
			
		||||
      showSubDialog: false,
 | 
			
		||||
      disableXXX: false,
 | 
			
		||||
      defaultQuillConfig: {
 | 
			
		||||
        modules: {
 | 
			
		||||
          toolbar: [
 | 
			
		||||
            [{ font: [] }],
 | 
			
		||||
            [{ size: ["small", false, "large", "huge"] }], // custom dropdown
 | 
			
		||||
            ["bold", "italic", "underline", "strike"], // toggled buttons
 | 
			
		||||
            [{ color: [] }, { background: [] }], // dropdown with defaults from theme
 | 
			
		||||
            ["blockquote", "code-block"],
 | 
			
		||||
            [{ header: 1 }, { header: 2 }], // custom button values
 | 
			
		||||
            [{ list: "ordered" }, { list: "bullet" }],
 | 
			
		||||
            // [{ 'script': 'sub'}, { 'script': 'super' }],      // superscript/subscript
 | 
			
		||||
            [{ indent: "-1" }, { indent: "+1" }], // outdent/indent
 | 
			
		||||
            // [{ 'direction': 'rtl' }],                         // text direction
 | 
			
		||||
            // [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
 | 
			
		||||
            // [{ 'align': [] }],
 | 
			
		||||
            // ['clean']                                         // remove formatting button
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
        theme: "snow",
 | 
			
		||||
        readOnly: false,
 | 
			
		||||
        placeholder: "在这里输入描述信息...",
 | 
			
		||||
        scrollingContainer: null,
 | 
			
		||||
      },
 | 
			
		||||
      attrPage: 1,
 | 
			
		||||
      attrSize: 10,
 | 
			
		||||
      attrTotal: 0,
 | 
			
		||||
      fileList: [],
 | 
			
		||||
      imgPreviewDialogVisible: false,
 | 
			
		||||
      currentImgUrl: "",
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.configs.form.rows.forEach((row) => {
 | 
			
		||||
      row.forEach((col) => {
 | 
			
		||||
        if (col.changeReflects && typeof col.changeReflects === 'object' && 'fromKey' in col.changeReflects && 'toProp' in col.changeReflects) {
 | 
			
		||||
          this.$watch(
 | 
			
		||||
            () => this.dataForm[col.prop],
 | 
			
		||||
            val => {
 | 
			
		||||
              if (val && (col.prop in this.cached)) {
 | 
			
		||||
                console.log("here changeReflects", col.prop, col.changeReflects.toProp, this.cached[col.prop])
 | 
			
		||||
                if (typeof col.changeReflects.fromKey === 'string') {
 | 
			
		||||
                  this.dataForm[col.changeReflects.toProp] = this.cached[col.prop].find(item => item.id === val)?.[col.changeReflects.fromKey]
 | 
			
		||||
                } else if (Array.isArray(col.changeReflects.fromKey) && col.changeReflects.delimiter) {
 | 
			
		||||
                  const foundItem = this.dataForm[col.changeReflects.toProp] = this.cached[col.prop].find(item => item.id === val)
 | 
			
		||||
                  if (foundItem) {
 | 
			
		||||
                    const values = col.changeReflects.fromKey.map(key => foundItem[key])
 | 
			
		||||
                    this.dataForm[col.changeReflects.toProp] = values.join(col.changeReflects.delimiter)
 | 
			
		||||
                  } else {
 | 
			
		||||
                    this.dataForm[col.changeReflects.toProp] = col.changeReflects.delimiter
 | 
			
		||||
                    console.log("[DialogWithMenu] mounted() 没找到对应数据")
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              immediate: false
 | 
			
		||||
            }
 | 
			
		||||
          )
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  watch: {
 | 
			
		||||
    dialogVisible: function (val) {
 | 
			
		||||
      if (!!val) {
 | 
			
		||||
        this.attrPage = 1
 | 
			
		||||
        this.attrSize = 10
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    actualMenus() {
 | 
			
		||||
      return this.configs.menu.filter((m) => {
 | 
			
		||||
        if (m.onlyEditMode && !this.dataForm.id) {
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    filteredTableProps() {
 | 
			
		||||
      return this.detailMode ? this.configs.table.props.filter((v) => v.prop !== "operations") : this.configs.table.props;
 | 
			
		||||
    },
 | 
			
		||||
    uploadHeaders() {
 | 
			
		||||
      return {
 | 
			
		||||
        token: Cookies.get("token") || "",
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    uploadUrl() {
 | 
			
		||||
      return this.configs.menu.find((item) => item.key === "attachment")?.actionUrl || "#";
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    disableCondition(prop) {
 | 
			
		||||
      return this.detailMode || (this.disableXXX && this.autoDisabledQueue.indexOf(prop) !== -1);
 | 
			
		||||
    },
 | 
			
		||||
    /** utitilities */
 | 
			
		||||
    showButton(operate) {
 | 
			
		||||
      const notDetailMode = !this.detailMode;
 | 
			
		||||
      const showAlways = operate.showAlways ?? false;
 | 
			
		||||
      const editMode = operate.showOnEdit && this.dataForm.id;
 | 
			
		||||
      const addMode = !operate.showOnEdit && !this.dataForm.id;
 | 
			
		||||
      const permission = operate.permission ? this.$hasPermission(operate.permission) : true;
 | 
			
		||||
      const currentMenuKey = this.configs.menu.find((item) => item.name === this.activeMenu)?.key;
 | 
			
		||||
      return notDetailMode && (showAlways || ((editMode || addMode) && permission)) && currentMenuKey === "info";
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    resetForm(excludeId = false, immediate = false) {
 | 
			
		||||
      setTimeout(
 | 
			
		||||
        () => {
 | 
			
		||||
          Object.keys(this.dataForm).forEach((key) => {
 | 
			
		||||
            if (excludeId && key === "id") return;
 | 
			
		||||
            if ("files" in this.dataForm) this.dataForm.files = [];
 | 
			
		||||
            if ("fileIds" in this.dataForm) this.dataForm.fileIds = [];
 | 
			
		||||
            else this.dataForm[key] = null;
 | 
			
		||||
            if (Array.isArray(this.fileList)) {
 | 
			
		||||
              this.fileList = [];
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
          this.activeMenu = this.configs.menu[0].name;
 | 
			
		||||
          this.$refs.dataForm[0].clearValidate();
 | 
			
		||||
        },
 | 
			
		||||
        immediate ? 0 : 200
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    updateOptions() {
 | 
			
		||||
      return new Promise((resolve, reject) => {
 | 
			
		||||
        if (this.watingToRefreshQueue.length) {
 | 
			
		||||
          this.watingToRefreshQueue.forEach((opt) => {
 | 
			
		||||
            console.log("[刷新数据, ", opt, "]");
 | 
			
		||||
            if ("fetchData" in opt) {
 | 
			
		||||
              opt.fetchData(this.dataForm.id ? this.dataForm.id : -1).then(({ data: res }) => {
 | 
			
		||||
                if (res.code === 0) {
 | 
			
		||||
                  this.$set(
 | 
			
		||||
                    opt,
 | 
			
		||||
                    "options",
 | 
			
		||||
                    "list" in res.data
 | 
			
		||||
                      ? res.data.list.map((i) => ({ label: i.code, value: i.id }))
 | 
			
		||||
                      : res.data.map((i) => ({ label: i.code, value: i.id }))
 | 
			
		||||
                  );
 | 
			
		||||
 | 
			
		||||
                  resolve({ done: true });
 | 
			
		||||
                } else {
 | 
			
		||||
                  this.$message({
 | 
			
		||||
                    message: `${res.code}: ${res.msg}`,
 | 
			
		||||
                    type: "error",
 | 
			
		||||
                    duration: 1500,
 | 
			
		||||
                  });
 | 
			
		||||
 | 
			
		||||
                  resolve({ done: false });
 | 
			
		||||
                }
 | 
			
		||||
              });
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
        } else resolve(null);
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** init **/
 | 
			
		||||
    init(id, detailMode, menu) {
 | 
			
		||||
      // this.dialogVisible = true;
 | 
			
		||||
      if (this.$refs.dataForm && this.$refs.dataForm.length) {
 | 
			
		||||
        // 当不是首次渲染dialog的时候,一开始就清空验证信息,本组件的循环里只有一个 dataForm 所以只用取 [0] 即可
 | 
			
		||||
        this.$refs.dataForm[0].clearValidate();
 | 
			
		||||
      }
 | 
			
		||||
      console.log("[dialog] DialogWithHead init():", id, detailMode);
 | 
			
		||||
 | 
			
		||||
      this.detailMode = detailMode ?? false;
 | 
			
		||||
      this.$nextTick(() => {
 | 
			
		||||
        this.dataForm.id = id || null;
 | 
			
		||||
        if (this.dataForm.id) {
 | 
			
		||||
          // 如果是编辑
 | 
			
		||||
          this.loadingStatus = true;
 | 
			
		||||
          // 提前获取属性列表
 | 
			
		||||
          this.getSubList();
 | 
			
		||||
          // 获取详情
 | 
			
		||||
          this.updateOptions().then((result) => {
 | 
			
		||||
            if (result === null || (typeof result === "object" && result.done)) {
 | 
			
		||||
              this.$http.get(this.urls.base + `/${this.dataForm.id}`).then(({ data: res }) => {
 | 
			
		||||
                if (res && res.code === 0) {
 | 
			
		||||
                  const dataFormKeys = Object.keys(this.dataForm);
 | 
			
		||||
                  this.dataForm = __pick(res.data, dataFormKeys);
 | 
			
		||||
                  if ("files" in res.data) {
 | 
			
		||||
                    console.log("[DialogWithMenu] fileList===>", res.data.files, this.fileList);
 | 
			
		||||
                    /** 返回的文件列表 */
 | 
			
		||||
                    this.fileList = res.data.files
 | 
			
		||||
                      ? res.data.files.map((file) => ({
 | 
			
		||||
                        id: file.id,
 | 
			
		||||
                        name: file.fileUrl.split("/").pop(),
 | 
			
		||||
                        url: file.fileUrl,
 | 
			
		||||
                        typeCode: file.typeCode,
 | 
			
		||||
                      }))
 | 
			
		||||
                      : [];
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
                this.loadingStatus = false;
 | 
			
		||||
                // 是否要跳转到附件页
 | 
			
		||||
                if (menu && menu.key) {
 | 
			
		||||
                  this.activeMenu = this.configs.menu.find((item) => item.key === menu.key)?.name;
 | 
			
		||||
                }
 | 
			
		||||
              });
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
        } else {
 | 
			
		||||
          // 如果不是编辑
 | 
			
		||||
          this.updateOptions();
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** handlers */
 | 
			
		||||
    handleFileClick(type, file) {
 | 
			
		||||
      switch (type) {
 | 
			
		||||
        case "view": {
 | 
			
		||||
          // 加载图片
 | 
			
		||||
          this.$http
 | 
			
		||||
            .get("/pms/attachment/downloadFile", {
 | 
			
		||||
              params: {
 | 
			
		||||
                attachmentId: file.id,
 | 
			
		||||
                type: 0, // 0 预览,1 下载
 | 
			
		||||
              },
 | 
			
		||||
              responseType: "blob",
 | 
			
		||||
            })
 | 
			
		||||
            .then(({ data: res }) => {
 | 
			
		||||
              console.log("preivew", res);
 | 
			
		||||
              if (/image/i.test(res.type)) {
 | 
			
		||||
                // 显示图片
 | 
			
		||||
                this.currentImgUrl = URL.createObjectURL(res);
 | 
			
		||||
                this.imgPreviewDialogVisible = true;
 | 
			
		||||
              } else if (/pdf/i.test(res.type)) {
 | 
			
		||||
                // 预览pdf 
 | 
			
		||||
                let a = document.createElement('a')
 | 
			
		||||
                a.setAttribute('target', '_blank')
 | 
			
		||||
                a.href = URL.createObjectURL(res)
 | 
			
		||||
                a.click()
 | 
			
		||||
                console.log('before remove a ', a)
 | 
			
		||||
                a.remove()
 | 
			
		||||
                console.log('removed a ', a)
 | 
			
		||||
              } else {
 | 
			
		||||
                this.$message({
 | 
			
		||||
                  message: "非图片和PDF文件请下载后预览",
 | 
			
		||||
                  type: "error",
 | 
			
		||||
                  duration: 1500,
 | 
			
		||||
                });
 | 
			
		||||
              }
 | 
			
		||||
            });
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case "download": {
 | 
			
		||||
          // 下载图片
 | 
			
		||||
          this.$http
 | 
			
		||||
            .get("/pms/attachment/downloadFile", {
 | 
			
		||||
              params: {
 | 
			
		||||
                attachmentId: file.id,
 | 
			
		||||
                type: 1, // 0 预览,1 下载
 | 
			
		||||
              },
 | 
			
		||||
              responseType: "blob",
 | 
			
		||||
            })
 | 
			
		||||
            .then(({ data: res }) => {
 | 
			
		||||
              const blob = new Blob([res]);
 | 
			
		||||
 | 
			
		||||
              /** 通知 */
 | 
			
		||||
              this.$notify({
 | 
			
		||||
                title: "成功",
 | 
			
		||||
                message: "开始下载",
 | 
			
		||||
                type: "success",
 | 
			
		||||
                duration: 1200,
 | 
			
		||||
              });
 | 
			
		||||
 | 
			
		||||
              if ("download" in document.createElement("a")) {
 | 
			
		||||
                const alink = document.createElement("a");
 | 
			
		||||
                alink.download = file.name;
 | 
			
		||||
                alink.style.display = "none";
 | 
			
		||||
                alink.target = "_blank";
 | 
			
		||||
                alink.href = URL.createObjectURL(blob);
 | 
			
		||||
                document.body.appendChild(alink);
 | 
			
		||||
                alink.click();
 | 
			
		||||
                URL.revokeObjectURL(alink.href);
 | 
			
		||||
                document.body.removeChild(alink);
 | 
			
		||||
              } else {
 | 
			
		||||
                navigator.msSaveBlob(blob, fileName);
 | 
			
		||||
              }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case "delete": {
 | 
			
		||||
          return this.$confirm(`确定删除图片: ${file.name}`, "提示", {
 | 
			
		||||
            confirmButtonText: "确认",
 | 
			
		||||
            cancelButtonText: "我再想想",
 | 
			
		||||
            type: "warning",
 | 
			
		||||
          })
 | 
			
		||||
            .then(() => {
 | 
			
		||||
              this.loadingStatus = true;
 | 
			
		||||
              const newFilelist = this.fileList.filter((f) => f.id !== file.id);
 | 
			
		||||
              this.updateRemoteFiles(newFilelist).then((msg) => {
 | 
			
		||||
                if (msg && msg === "success") {
 | 
			
		||||
                  this.fileList = newFilelist;
 | 
			
		||||
                  this.loadingStatus = false;
 | 
			
		||||
                  /** 通知 */
 | 
			
		||||
                  this.$notify({
 | 
			
		||||
                    title: "成功",
 | 
			
		||||
                    message: "已删除",
 | 
			
		||||
                    type: "success",
 | 
			
		||||
                    duration: 1200,
 | 
			
		||||
                  });
 | 
			
		||||
                }
 | 
			
		||||
              });
 | 
			
		||||
            })
 | 
			
		||||
            .catch((err) => { });
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleUploadSuccess(response, file, fileList) {
 | 
			
		||||
      console.log("[DialogWithMenu] uploadedFileList", response, file, fileList);
 | 
			
		||||
 | 
			
		||||
      if (response.code === 0) {
 | 
			
		||||
        const uploadedFile = response.data[0];
 | 
			
		||||
        const fileItem = {
 | 
			
		||||
          id: uploadedFile.id,
 | 
			
		||||
          name: uploadedFile.fileUrl.split("/").pop(),
 | 
			
		||||
          url: uploadedFile.fileUrl,
 | 
			
		||||
          typeCode: file.typeCode,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        this.loadingStatus = true;
 | 
			
		||||
        this.updateRemoteFiles([...this.fileList, fileItem]).then((msg) => {
 | 
			
		||||
          if (msg && msg === "success") {
 | 
			
		||||
            this.fileList.push(fileItem);
 | 
			
		||||
            this.loadingStatus = false;
 | 
			
		||||
            /** 通知 */
 | 
			
		||||
            this.$notify({
 | 
			
		||||
              title: "成功",
 | 
			
		||||
              message: "上传成功",
 | 
			
		||||
              type: "success",
 | 
			
		||||
              duration: 1200,
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    updateRemoteFiles(filelist) {
 | 
			
		||||
      return this.$http
 | 
			
		||||
        .put("/pms/product", {
 | 
			
		||||
          id: "id" in this.dataForm ? this.dataForm.id : "DEFAULT_ID",
 | 
			
		||||
          fileIds: filelist.map((f) => f.id),
 | 
			
		||||
        })
 | 
			
		||||
        .then(({ data: res }) => {
 | 
			
		||||
          if (res.code === 0) return "success";
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleUploadCheck(file) {
 | 
			
		||||
      console.log("[before upload]", file);
 | 
			
		||||
      const LIMIT = 2 * 1024 * 1024; // bytes
 | 
			
		||||
      if (file.size > LIMIT) {
 | 
			
		||||
        this.$message({
 | 
			
		||||
          message: "文件大小不能超过 2MB",
 | 
			
		||||
          type: "error",
 | 
			
		||||
          duration: 1500,
 | 
			
		||||
        });
 | 
			
		||||
        return false;
 | 
			
		||||
      } else return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleComponentModelUpdate(propName, { subject, payload: { data } }) {
 | 
			
		||||
      this.dataForm[propName] = JSON.stringify(data);
 | 
			
		||||
      console.log("[DialogJustForm] handleComponentModelUpdate", this.dataForm[propName]);
 | 
			
		||||
    },
 | 
			
		||||
    handleSelectChange(col, eventValue) {
 | 
			
		||||
      console.log("[dialog] select change: ", col, eventValue);
 | 
			
		||||
    },
 | 
			
		||||
    handleSwitchChange(val) {
 | 
			
		||||
      console.log("[dialog] switch change: ", val, this.dataForm);
 | 
			
		||||
    },
 | 
			
		||||
    handleBtnClick(payload) {
 | 
			
		||||
      console.log("btn click payload: ", payload);
 | 
			
		||||
 | 
			
		||||
      if ("name" in payload) {
 | 
			
		||||
        switch (payload.name) {
 | 
			
		||||
          case "cancel":
 | 
			
		||||
            this.handleClose();
 | 
			
		||||
            break;
 | 
			
		||||
          case "reset":
 | 
			
		||||
            this.resetForm(true, true); // true means exclude id
 | 
			
		||||
            break;
 | 
			
		||||
          case "add":
 | 
			
		||||
          case "update": {
 | 
			
		||||
            this.$refs.dataForm[0].validate((passed, result) => {
 | 
			
		||||
              if (passed) {
 | 
			
		||||
                // 如果通过验证
 | 
			
		||||
                this.btnLoading = true
 | 
			
		||||
                this.loadingStatus = true;
 | 
			
		||||
                const method = payload.name === "add" ? "POST" : "PUT";
 | 
			
		||||
 | 
			
		||||
                // 判断是否有附件选项
 | 
			
		||||
                const hasAttachment = !!this.configs.menu.find((item) => item.key === "attachment");
 | 
			
		||||
                if (hasAttachment) {
 | 
			
		||||
                  const fileIds = this.fileList.map((item) => item.id);
 | 
			
		||||
                  this.$set(this.dataForm, "fileIds", fileIds);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // 加载额外需要的 id
 | 
			
		||||
                let extraIds = {};
 | 
			
		||||
                if (this.configs.extraIds && typeof this.configs.extraIds === "object") {
 | 
			
		||||
                  // 如果配置里,有 extraIds 选项
 | 
			
		||||
                  Object.entries(this.configs.extraIds).forEach(([key, value]) => {
 | 
			
		||||
                    extraIds[key] = value;
 | 
			
		||||
                  });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // 实际发送请求
 | 
			
		||||
                this.btnLoading = true
 | 
			
		||||
                this.$http({
 | 
			
		||||
                  url: this.urls.base,
 | 
			
		||||
                  method,
 | 
			
		||||
                  data: {
 | 
			
		||||
                    ...extraIds,
 | 
			
		||||
                    ...this.dataForm,
 | 
			
		||||
                  },
 | 
			
		||||
                })
 | 
			
		||||
                  .then(({ data: res }) => {
 | 
			
		||||
                    this.btnLoading = false
 | 
			
		||||
                    this.loadingStatus = false;
 | 
			
		||||
                    console.log("[add&update] res is: ", res);
 | 
			
		||||
                    if (res.code === 0) {
 | 
			
		||||
                      this.$message.success(payload.name === "add" ? "添加成功" : "更新成功");
 | 
			
		||||
                      this.$emit("refreshDataList");
 | 
			
		||||
 | 
			
		||||
                      // 如果 watingToRefreshQueue 队列里有数据
 | 
			
		||||
                      // if (this.watingToRefreshQueue.length) {
 | 
			
		||||
                      //   // 刷新队列
 | 
			
		||||
                      //   this.watingToRefreshQueue.forEach((opt) => {
 | 
			
		||||
                      //     console.log("[刷新数据, ", opt, "]");
 | 
			
		||||
                      //     if ("fetchData" in opt) {
 | 
			
		||||
                      //       opt.fetchData().then(({ data: res }) => {
 | 
			
		||||
                      //         if (res.code === 0) {
 | 
			
		||||
                      //           this.$set(
 | 
			
		||||
                      //             opt,
 | 
			
		||||
                      //             "options",
 | 
			
		||||
                      //             "list" in res.data
 | 
			
		||||
                      //               ? res.data.list.map((i) => ({ label: i.name, value: i.id }))
 | 
			
		||||
                      //               : res.data.map((i) => ({ label: i.name, value: i.id }))
 | 
			
		||||
                      //           );
 | 
			
		||||
                      //         }
 | 
			
		||||
                      //       });
 | 
			
		||||
                      //     }
 | 
			
		||||
                      //   });
 | 
			
		||||
                      // }
 | 
			
		||||
 | 
			
		||||
                      this.handleClose();
 | 
			
		||||
                    } else {
 | 
			
		||||
                      this.$message({
 | 
			
		||||
                        message: `${res.code}: ${res.msg}`,
 | 
			
		||||
                        type: "error",
 | 
			
		||||
                        duration: 2000,
 | 
			
		||||
                      });
 | 
			
		||||
                      if (this.btnLoading) this.btnLoading = false
 | 
			
		||||
                    }
 | 
			
		||||
                  })
 | 
			
		||||
                  .catch((errMsg) => {
 | 
			
		||||
                    this.$message.error("参数错误:" + errMsg);
 | 
			
		||||
                    if (this.loadingStatus) this.loadingStatus = false;
 | 
			
		||||
                    if (this.btnLoading) this.btnLoading = false
 | 
			
		||||
                  });
 | 
			
		||||
              } else {
 | 
			
		||||
                this.$message.error("请核查字段信息");
 | 
			
		||||
              }
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    handleTabClick(payload) {
 | 
			
		||||
      //   console.log("tab click payload: ", this.activeMenu);
 | 
			
		||||
      //   if (this.activeMenu === this.configs.menu[1].name) {
 | 
			
		||||
      //     // 获取数据
 | 
			
		||||
      //     this.getSubList();
 | 
			
		||||
      //   }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handlePageChange(val) {
 | 
			
		||||
      this.getSubList(val, this.attrSize);
 | 
			
		||||
    },
 | 
			
		||||
    handleSizeChange(val) {
 | 
			
		||||
      this.attrPage = 1;
 | 
			
		||||
      this.attrSize = val
 | 
			
		||||
      this.getSubList(1, val);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getSubList(page, size) {
 | 
			
		||||
      const params = {};
 | 
			
		||||
      params.page = page ?? this.attrPage;
 | 
			
		||||
      params.limit = size ?? this.attrSize;
 | 
			
		||||
 | 
			
		||||
      const requiredParams = this.configs.table.extraParams;
 | 
			
		||||
      if (requiredParams) {
 | 
			
		||||
        if (Array.isArray(requiredParams)) {
 | 
			
		||||
          requiredParams.forEach((str) => {
 | 
			
		||||
            if (/id/i.test(str)) {
 | 
			
		||||
              params[str] = this.dataForm.id;
 | 
			
		||||
            } else {
 | 
			
		||||
              params[str] = "";
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
        } else if (typeof requiredParams === "string") {
 | 
			
		||||
          // 如果需要额外参数,一般肯定需要
 | 
			
		||||
          params[this.configs.table.extraParams] = this.dataForm.id;
 | 
			
		||||
          // 此时 dataForm.id 一定是存在的
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      this.$http.get(this.urls.subpage, { params }).then(({ data: res }) => {
 | 
			
		||||
        console.log("[DialogWithMenu] getSubList:", res);
 | 
			
		||||
        if (res.code === 0 && res.data?.list) {
 | 
			
		||||
          // 有数据
 | 
			
		||||
          this.subList = res.data.list;
 | 
			
		||||
          this.attrTotal = res.data.total;
 | 
			
		||||
        } else {
 | 
			
		||||
          this.subList.splice(0);
 | 
			
		||||
          this.attrTotal = 0;
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleAddParam(id) {
 | 
			
		||||
      this.showSubDialog = true;
 | 
			
		||||
      this.$nextTick(() => {
 | 
			
		||||
        this.$refs.subDialog.init(id ?? null);
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleClose() {
 | 
			
		||||
      this.resetForm();
 | 
			
		||||
      this.$emit("update:dialogVisible", false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** 列表handlers */
 | 
			
		||||
    handleAddItem() {
 | 
			
		||||
      // console.log('[dialog] handleAddItem ot list...');
 | 
			
		||||
      this.showBaseDialog = true;
 | 
			
		||||
      this.$nextTick(() => {
 | 
			
		||||
        console.log("[sub-dialog] ", this.$refs["sub-dialog"].init());
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    handleTableRowOperate({ type, data }) {
 | 
			
		||||
      console.log("handleTableRowOperate", type, data);
 | 
			
		||||
 | 
			
		||||
      switch (type) {
 | 
			
		||||
        case "delete": {
 | 
			
		||||
          // 确认是否删除
 | 
			
		||||
          console.log('delete....', data)
 | 
			
		||||
          const itemName = typeof data === 'object' ? (data.attrName || data.name || data.material || data.id) : data
 | 
			
		||||
          return this.$confirm(`是否删除条目: ${itemName}`, "提示", {
 | 
			
		||||
            confirmButtonText: "确认",
 | 
			
		||||
            cancelButtonText: "我再想想",
 | 
			
		||||
            type: "warning",
 | 
			
		||||
          })
 | 
			
		||||
            .then(() => {
 | 
			
		||||
              // this.$http.delete(this.urls.base + `/${data}`).then((res) => {
 | 
			
		||||
              this.$http({
 | 
			
		||||
                url: this.urls.subase,
 | 
			
		||||
                method: "DELETE",
 | 
			
		||||
                data: [`${data.id}`],
 | 
			
		||||
              }).then(({ data: res }) => {
 | 
			
		||||
                if (res.code === 0) {
 | 
			
		||||
                  this.$message.success({
 | 
			
		||||
                    message: "删除成功!",
 | 
			
		||||
                    duration: 1000,
 | 
			
		||||
                    onClose: () => {
 | 
			
		||||
                      this.getSubList(1, 20);
 | 
			
		||||
                    },
 | 
			
		||||
                  });
 | 
			
		||||
                }
 | 
			
		||||
              });
 | 
			
		||||
            })
 | 
			
		||||
            .catch((err) => { });
 | 
			
		||||
        }
 | 
			
		||||
        case "edit": {
 | 
			
		||||
          this.handleAddParam(data); /** data is ==> id */
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        // case 'view-detail-action':
 | 
			
		||||
        // 	this.openDialog(data, true);
 | 
			
		||||
        // 	break;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.el-menu {
 | 
			
		||||
  margin: 16px 0 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.el-menu.el-menu--horizontal {
 | 
			
		||||
  border: none !important;
 | 
			
		||||
  /* background: #0f02 !important; */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* .el-menu--horizontal > .el-menu-item.is-active { */
 | 
			
		||||
/* border-bottom-color: #0b58ff; */
 | 
			
		||||
/* } */
 | 
			
		||||
 | 
			
		||||
.dialog-with-menu>>>.el-dialog__body {
 | 
			
		||||
  /* padding-top: 16px !important;
 | 
			
		||||
  padding-bottom: 16px !important; */
 | 
			
		||||
  padding-top: 0 !important;
 | 
			
		||||
  padding-bottom: 0 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.el-select,
 | 
			
		||||
.el-cascader {
 | 
			
		||||
  width: 100% !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dialog-with-menu>>>.el-dialog__header {
 | 
			
		||||
  padding: 10px 20px 10px;
 | 
			
		||||
  /* background: linear-gradient(to bottom, rgba(0, 0, 0, 0.25), white); */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.relative {
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.at-right-top {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  z-index: 10000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ul.file-list,
 | 
			
		||||
ul.file-list>li {
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  list-style: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.file-list {
 | 
			
		||||
  max-height: 20vh;
 | 
			
		||||
  overflow-y: auto;
 | 
			
		||||
  margin-top: 12px;
 | 
			
		||||
  /* width: 240px; */
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ul.file-list>li {
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  background-color: #edededd2;
 | 
			
		||||
  padding: 8px;
 | 
			
		||||
  margin-bottom: 2px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ul.file-list>li:hover {
 | 
			
		||||
  background-color: #ededed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.file-operations {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.file-icon {
 | 
			
		||||
  margin-right: 8px;
 | 
			
		||||
  font-size: 16px;
 | 
			
		||||
  line-height: 1;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  place-content: center;
 | 
			
		||||
  width: 16px;
 | 
			
		||||
  height: 16px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* .image-preview-dialog {
 | 
			
		||||
} */
 | 
			
		||||
 | 
			
		||||
.force-disabled {
 | 
			
		||||
  margin-top: 42px;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -46,35 +46,36 @@
 | 
			
		||||
					}}文件大小不超过2MB
 | 
			
		||||
				</div>
 | 
			
		||||
			</el-upload>
 | 
			
		||||
			<!-- <div
 | 
			
		||||
				class="file-list__item"
 | 
			
		||||
				v-for="n in 9"
 | 
			
		||||
				:key="n"
 | 
			
		||||
				:style="{
 | 
			
		||||
					display: n > 4 && !expand ? 'none' : 'block',
 | 
			
		||||
				}"
 | 
			
		||||
				:data-name="n"
 | 
			
		||||
				:class="{ 'default-icon': !isPicMode }">
 | 
			
		||||
				<i class="el-icon-delete"></i>
 | 
			
		||||
			</div> -->
 | 
			
		||||
			<div
 | 
			
		||||
				class="file-list__item"
 | 
			
		||||
				v-for="(file, index) in files"
 | 
			
		||||
				:key="file.fileName"
 | 
			
		||||
				:style="{
 | 
			
		||||
					background: isPicMode
 | 
			
		||||
						? `url(${file.fileUrl}) no-repeat`
 | 
			
		||||
						: `url(${defaultBg}) no-repeat`,
 | 
			
		||||
					backgroundSize: isPicMode ? '100% 100%' : '64px',
 | 
			
		||||
					backgroundPosition: isPicMode ? '0% 0%' : 'center',
 | 
			
		||||
				}"
 | 
			
		||||
				:data-name="file.fileName">
 | 
			
		||||
				<el-button
 | 
			
		||||
					v-if="!disabled"
 | 
			
		||||
					type="text"
 | 
			
		||||
					class="el-icon-delete"
 | 
			
		||||
					style="padding: 0"
 | 
			
		||||
					@click="(e) => handleDelete(file)" />
 | 
			
		||||
				style="width: 100%">
 | 
			
		||||
				<div
 | 
			
		||||
					class="file-list__item"
 | 
			
		||||
					v-if="!isPicMode"
 | 
			
		||||
					:style="{
 | 
			
		||||
						background: isPicMode
 | 
			
		||||
							? `url(${file.fileUrl}) no-repeat`
 | 
			
		||||
							: `url(${defaultBg}) no-repeat`,
 | 
			
		||||
						backgroundSize: isPicMode ? '100% 100%' : '64px',
 | 
			
		||||
						backgroundPosition: isPicMode ? '0% 0%' : 'center',
 | 
			
		||||
					}"
 | 
			
		||||
					@click="handleDownload(file)"
 | 
			
		||||
					:data-name="file.fileName">
 | 
			
		||||
					<el-button
 | 
			
		||||
						v-if="!disabled"
 | 
			
		||||
						type="text"
 | 
			
		||||
						class="el-icon-delete"
 | 
			
		||||
						style="padding: 0"
 | 
			
		||||
						@click="(e) => handleDelete(file)" />
 | 
			
		||||
				</div>
 | 
			
		||||
 | 
			
		||||
				<el-image
 | 
			
		||||
					v-else
 | 
			
		||||
					class="file-list__item"
 | 
			
		||||
					style="width: 100%"
 | 
			
		||||
					:src="file.fileUrl"
 | 
			
		||||
					:preview-src-list="files.map((item) => item.fileUrl)"></el-image>
 | 
			
		||||
			</div>
 | 
			
		||||
		</section>
 | 
			
		||||
	</div>
 | 
			
		||||
@@ -189,6 +190,32 @@ export default {
 | 
			
		||||
			}, 500);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		async handleDownload(file) {
 | 
			
		||||
			if (this.isPicMode) {
 | 
			
		||||
				// this.$emit('preview', file);
 | 
			
		||||
				const link = document.createElement('a');
 | 
			
		||||
				link.href = file.fileUrl;
 | 
			
		||||
				link.target = '_blank';
 | 
			
		||||
				document.body.appendChild(link);
 | 
			
		||||
				link.click();
 | 
			
		||||
				document.body.removeChild(link);
 | 
			
		||||
			} else {
 | 
			
		||||
				// this.$emit('download', file);
 | 
			
		||||
				const data = await this.$axios({
 | 
			
		||||
					url: file.fileUrl,
 | 
			
		||||
					method: 'get',
 | 
			
		||||
					responseType: 'blob',
 | 
			
		||||
				});
 | 
			
		||||
				const link = document.createElement('a');
 | 
			
		||||
				link.href = window.URL.createObjectURL(new Blob([data]));
 | 
			
		||||
				link.download = file.fileName;
 | 
			
		||||
				document.body.appendChild(link);
 | 
			
		||||
				link.click();
 | 
			
		||||
				document.body.removeChild(link);
 | 
			
		||||
				window.URL.revokeObjectURL(link.href);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		emitFilelist() {
 | 
			
		||||
			this.$emit('update', this.files);
 | 
			
		||||
		},
 | 
			
		||||
 
 | 
			
		||||
@@ -42,16 +42,26 @@
 | 
			
		||||
							v-model="form" />
 | 
			
		||||
					</div>
 | 
			
		||||
 | 
			
		||||
					<div v-if="section.key == 'attrs'" style="margin-top: 12px">
 | 
			
		||||
					<div
 | 
			
		||||
						v-if="section.key == 'attrs'"
 | 
			
		||||
						style="margin-top: 12px; position: relative">
 | 
			
		||||
						<div
 | 
			
		||||
							v-if="!mode.includes('detail')"
 | 
			
		||||
							style="position: absolute; top: -40px; right: 0">
 | 
			
		||||
							<el-button @click="handleAddAttr" type="text">
 | 
			
		||||
								<i class="el-icon-plus"></i>
 | 
			
		||||
								添加属性
 | 
			
		||||
							</el-button>
 | 
			
		||||
						</div>
 | 
			
		||||
						<base-table
 | 
			
		||||
							v-loading="attrListLoading"
 | 
			
		||||
							:table-props="section.props"
 | 
			
		||||
							:page="attrQuery?.params.pageNo || 1"
 | 
			
		||||
							:limit="attrQuery?.params.pageSize || 10"
 | 
			
		||||
							:table-data="list"
 | 
			
		||||
							:add-button-show="mode.includes('detail') ? null : '添加属性'"
 | 
			
		||||
							@emitButtonClick="handleAddAttr"
 | 
			
		||||
							@emitFun="handleEmitFun">
 | 
			
		||||
							<!-- :add-button-show="mode.includes('detail') ? null : '添加属性'"
 | 
			
		||||
							@emitButtonClick="handleAddAttr" -->
 | 
			
		||||
							<method-btn
 | 
			
		||||
								v-if="section.tableBtn"
 | 
			
		||||
								slot="handleBtn"
 | 
			
		||||
@@ -76,7 +86,7 @@
 | 
			
		||||
				<el-button v-if="mode == 'detail'" type="primary" @click="toggleEdit">
 | 
			
		||||
					编辑
 | 
			
		||||
				</el-button>
 | 
			
		||||
				<el-button v-else type="primary" @click="handleConfirm">确定</el-button>
 | 
			
		||||
				<el-button v-else type="primary" @click="handleConfirm">保存</el-button>
 | 
			
		||||
				<!-- sections的第二项必须是 属性列表  -->
 | 
			
		||||
				<!-- <el-button
 | 
			
		||||
						v-if="sections[1].allowAdd"
 | 
			
		||||
@@ -162,7 +172,9 @@ export default {
 | 
			
		||||
						input: true,
 | 
			
		||||
						label: '属性名称',
 | 
			
		||||
						prop: 'name',
 | 
			
		||||
						rules: [{ required: true, message: '属性名称不能为空', trigger: 'blur' }],
 | 
			
		||||
						rules: [
 | 
			
		||||
							{ required: true, message: '属性名称不能为空', trigger: 'blur' },
 | 
			
		||||
						],
 | 
			
		||||
					},
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
 
 | 
			
		||||
@@ -1,29 +1,62 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="app-container">
 | 
			
		||||
		<!-- 搜索工作栏 -->
 | 
			
		||||
		<SearchBar :formConfigs="searchBarFormConfig" ref="search-bar" @headBtnClick="handleSearchBarBtnClick" />
 | 
			
		||||
		<SearchBar
 | 
			
		||||
			:formConfigs="searchBarFormConfig"
 | 
			
		||||
			ref="search-bar"
 | 
			
		||||
			@headBtnClick="handleSearchBarBtnClick" />
 | 
			
		||||
 | 
			
		||||
		<!-- 列表 -->
 | 
			
		||||
		<base-table :table-props="tableProps" :page="queryParams.pageNo" :limit="queryParams.pageSize" :table-data="list"
 | 
			
		||||
		<base-table
 | 
			
		||||
			:table-props="tableProps"
 | 
			
		||||
			:page="queryParams.pageNo"
 | 
			
		||||
			:limit="queryParams.pageSize"
 | 
			
		||||
			:table-data="list"
 | 
			
		||||
			@emitFun="handleEmitFun">
 | 
			
		||||
			<method-btn v-if="tableBtn.length" slot="handleBtn" :width="120" label="操作" :method-list="tableBtn"
 | 
			
		||||
			<method-btn
 | 
			
		||||
				v-if="tableBtn.length"
 | 
			
		||||
				slot="handleBtn"
 | 
			
		||||
				:width="120"
 | 
			
		||||
				label="操作"
 | 
			
		||||
				:method-list="tableBtn"
 | 
			
		||||
				@clickBtn="handleTableBtnClick" />
 | 
			
		||||
		</base-table>
 | 
			
		||||
 | 
			
		||||
		<!-- 分页组件 -->
 | 
			
		||||
		<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
 | 
			
		||||
		<pagination
 | 
			
		||||
			v-show="total > 0"
 | 
			
		||||
			:total="total"
 | 
			
		||||
			:page.sync="queryParams.pageNo"
 | 
			
		||||
			:limit.sync="queryParams.pageSize"
 | 
			
		||||
			@pagination="getList" />
 | 
			
		||||
 | 
			
		||||
		<!-- 对话框(添加) -->
 | 
			
		||||
		<base-dialog :dialogTitle="title" :dialogVisible="open" @close="cancel" @cancel="cancel" width="60%"
 | 
			
		||||
		<base-dialog
 | 
			
		||||
			:dialogTitle="title"
 | 
			
		||||
			:dialogVisible="open"
 | 
			
		||||
			@close="cancel"
 | 
			
		||||
			@cancel="cancel"
 | 
			
		||||
			width="60%"
 | 
			
		||||
			@confirm="submitForm">
 | 
			
		||||
			<DialogForm v-if="open" key="index-dialog-form" ref="form" label-position="top" size="small" v-model="form"
 | 
			
		||||
			<DialogForm
 | 
			
		||||
				v-if="open"
 | 
			
		||||
				key="index-dialog-form"
 | 
			
		||||
				ref="form"
 | 
			
		||||
				label-position="top"
 | 
			
		||||
				size="small"
 | 
			
		||||
				v-model="form"
 | 
			
		||||
				:has-files="['files', 'files2']"
 | 
			
		||||
				:rows="computedRows" />
 | 
			
		||||
		</base-dialog>
 | 
			
		||||
 | 
			
		||||
		<!-- 设备 详情 - 编辑 -->
 | 
			
		||||
		<EquipmentDrawer v-if="editVisible" ref="drawer" :mode="editMode" @update-mode="editMode = $event"
 | 
			
		||||
			:data-id="form.id" :sections="[
 | 
			
		||||
		<EquipmentDrawer
 | 
			
		||||
			v-if="editVisible"
 | 
			
		||||
			ref="drawer"
 | 
			
		||||
			:mode="editMode"
 | 
			
		||||
			@update-mode="editMode = $event"
 | 
			
		||||
			:data-id="form.id"
 | 
			
		||||
			:sections="[
 | 
			
		||||
				{
 | 
			
		||||
					name: '基本信息',
 | 
			
		||||
					key: 'base',
 | 
			
		||||
@@ -50,20 +83,23 @@
 | 
			
		||||
					tableBtn: [
 | 
			
		||||
						this.$auth.hasPermi('base:core-equipment-attr:update')
 | 
			
		||||
							? {
 | 
			
		||||
								type: 'edit',
 | 
			
		||||
								btnName: '修改',
 | 
			
		||||
							}
 | 
			
		||||
									type: 'edit',
 | 
			
		||||
									btnName: '修改',
 | 
			
		||||
							  }
 | 
			
		||||
							: undefined,
 | 
			
		||||
						this.$auth.hasPermi('base:core-equipment-attr:delete')
 | 
			
		||||
							? {
 | 
			
		||||
								type: 'delete',
 | 
			
		||||
								btnName: '删除',
 | 
			
		||||
							}
 | 
			
		||||
									type: 'delete',
 | 
			
		||||
									btnName: '删除',
 | 
			
		||||
							  }
 | 
			
		||||
							: undefined,
 | 
			
		||||
					].filter((v) => v),
 | 
			
		||||
					allowAdd: true,
 | 
			
		||||
				},
 | 
			
		||||
			]" @refreshDataList="getList" @cancel="cancelEdit" @destroy="cancelEdit" />
 | 
			
		||||
			]"
 | 
			
		||||
			@refreshDataList="getList"
 | 
			
		||||
			@cancel="cancelEdit"
 | 
			
		||||
			@destroy="cancelEdit" />
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@@ -96,21 +132,21 @@ export default {
 | 
			
		||||
			tableBtn: [
 | 
			
		||||
				this.$auth.hasPermi(`base:core-equipment:update`)
 | 
			
		||||
					? {
 | 
			
		||||
						type: 'detail',
 | 
			
		||||
						btnName: '详情',
 | 
			
		||||
					}
 | 
			
		||||
							type: 'detail',
 | 
			
		||||
							btnName: '详情',
 | 
			
		||||
					  }
 | 
			
		||||
					: undefined,
 | 
			
		||||
				this.$auth.hasPermi('base:core-equipment:update')
 | 
			
		||||
					? {
 | 
			
		||||
						type: 'edit',
 | 
			
		||||
						btnName: '修改',
 | 
			
		||||
					}
 | 
			
		||||
							type: 'edit',
 | 
			
		||||
							btnName: '修改',
 | 
			
		||||
					  }
 | 
			
		||||
					: undefined,
 | 
			
		||||
				this.$auth.hasPermi('base:core-equipment:delete')
 | 
			
		||||
					? {
 | 
			
		||||
						type: 'delete',
 | 
			
		||||
						btnName: '删除',
 | 
			
		||||
					}
 | 
			
		||||
							type: 'delete',
 | 
			
		||||
							btnName: '删除',
 | 
			
		||||
					  }
 | 
			
		||||
					: undefined,
 | 
			
		||||
			].filter((v) => v),
 | 
			
		||||
			tableProps: [
 | 
			
		||||
@@ -176,14 +212,18 @@ export default {
 | 
			
		||||
					type: 'separate',
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					type: this.$auth.hasPermi('base:core-equipment:export') ? 'button' : '',
 | 
			
		||||
					type: this.$auth.hasPermi('base:core-equipment:export')
 | 
			
		||||
						? 'button'
 | 
			
		||||
						: '',
 | 
			
		||||
					btnName: '导出',
 | 
			
		||||
					name: 'export',
 | 
			
		||||
					plain: true,
 | 
			
		||||
					color: 'primary',
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					type: this.$auth.hasPermi('base:core-equipment:create') ? 'button' : '',
 | 
			
		||||
					type: this.$auth.hasPermi('base:core-equipment:create')
 | 
			
		||||
						? 'button'
 | 
			
		||||
						: '',
 | 
			
		||||
					btnName: '新增',
 | 
			
		||||
					name: 'add',
 | 
			
		||||
					plain: true,
 | 
			
		||||
@@ -196,7 +236,9 @@ export default {
 | 
			
		||||
						input: true,
 | 
			
		||||
						label: '设备名称',
 | 
			
		||||
						prop: 'name',
 | 
			
		||||
						rules: [{ required: true, message: '设备名称不能为空', trigger: 'blur' }],
 | 
			
		||||
						rules: [
 | 
			
		||||
							{ required: true, message: '设备名称不能为空', trigger: 'blur' },
 | 
			
		||||
						],
 | 
			
		||||
						// bind: {
 | 
			
		||||
						// 	disabled: this.editMode == 'detail', // some condition, like detail mode...
 | 
			
		||||
						// }
 | 
			
		||||
@@ -225,7 +267,9 @@ export default {
 | 
			
		||||
						label: '设备类型',
 | 
			
		||||
						prop: 'equipmentTypeId',
 | 
			
		||||
						url: '/base/core-equipment-type/page?pageNo=1&pageSize=100',
 | 
			
		||||
						rules: [{ required: true, message: '设备类型不能为空', trigger: 'blur' }],
 | 
			
		||||
						rules: [
 | 
			
		||||
							{ required: true, message: '设备类型不能为空', trigger: 'blur' },
 | 
			
		||||
						],
 | 
			
		||||
						bind: {
 | 
			
		||||
							filterable: true,
 | 
			
		||||
						},
 | 
			
		||||
@@ -235,7 +279,11 @@ export default {
 | 
			
		||||
						label: '预计生产时间(min/天)',
 | 
			
		||||
						prop: 'workTime',
 | 
			
		||||
						rules: [
 | 
			
		||||
							{ required: true, message: '预计生产时间不能为空', trigger: 'blur' },
 | 
			
		||||
							{
 | 
			
		||||
								required: true,
 | 
			
		||||
								message: '预计生产时间不能为空',
 | 
			
		||||
								trigger: 'blur',
 | 
			
		||||
							},
 | 
			
		||||
							{
 | 
			
		||||
								type: 'number',
 | 
			
		||||
								message: '请输入正确的数字值',
 | 
			
		||||
@@ -291,7 +339,11 @@ export default {
 | 
			
		||||
						label: '单件产品加工时间(s)',
 | 
			
		||||
						prop: 'processingTime',
 | 
			
		||||
						rules: [
 | 
			
		||||
							{ required: true, message: '单件产品加工时间不能为空', trigger: 'blur' },
 | 
			
		||||
							{
 | 
			
		||||
								required: true,
 | 
			
		||||
								message: '单件产品加工时间不能为空',
 | 
			
		||||
								trigger: 'blur',
 | 
			
		||||
							},
 | 
			
		||||
							{
 | 
			
		||||
								type: 'number',
 | 
			
		||||
								message: '请输入正确的数字值',
 | 
			
		||||
@@ -322,13 +374,19 @@ export default {
 | 
			
		||||
				[
 | 
			
		||||
					{
 | 
			
		||||
						upload: true,
 | 
			
		||||
						label: '上传资料',
 | 
			
		||||
						label: '设备资料',
 | 
			
		||||
						prop: 'files',
 | 
			
		||||
					},
 | 
			
		||||
				],
 | 
			
		||||
				[
 | 
			
		||||
					{ input: true, label: '备注', prop: 'remark' }
 | 
			
		||||
					{
 | 
			
		||||
						upload: true,
 | 
			
		||||
						label: '设备图片',
 | 
			
		||||
						prop: 'files2',
 | 
			
		||||
						fileType: 1,
 | 
			
		||||
					},
 | 
			
		||||
				],
 | 
			
		||||
				[{ input: true, label: '备注', prop: 'remark' }],
 | 
			
		||||
				// [
 | 
			
		||||
				// 	{
 | 
			
		||||
				// 		assetUpload: true,
 | 
			
		||||
@@ -429,7 +487,7 @@ export default {
 | 
			
		||||
			// 表单参数
 | 
			
		||||
			form: {
 | 
			
		||||
				id: null,
 | 
			
		||||
				files: []
 | 
			
		||||
				files: [],
 | 
			
		||||
			},
 | 
			
		||||
			showUploadComponents: false, // 是否显示上传组件
 | 
			
		||||
		};
 | 
			
		||||
@@ -441,36 +499,36 @@ export default {
 | 
			
		||||
		computedRows() {
 | 
			
		||||
			return this.showUploadComponents
 | 
			
		||||
				? [
 | 
			
		||||
					...this.rows,
 | 
			
		||||
					[
 | 
			
		||||
						{
 | 
			
		||||
							assetUpload: true,
 | 
			
		||||
							key: 'eq-assets', // 用于区分不同的上传组件
 | 
			
		||||
							label: '上传资料',
 | 
			
		||||
							fieldName: 'assets',
 | 
			
		||||
							subcomponent: AssetsUpload,
 | 
			
		||||
							prop: 'uploadedAssets',
 | 
			
		||||
							default: [],
 | 
			
		||||
							bind: {
 | 
			
		||||
								'is-pic-mode': false,
 | 
			
		||||
						...this.rows,
 | 
			
		||||
						[
 | 
			
		||||
							{
 | 
			
		||||
								assetUpload: true,
 | 
			
		||||
								key: 'eq-assets', // 用于区分不同的上传组件
 | 
			
		||||
								label: '上传资料',
 | 
			
		||||
								fieldName: 'assets',
 | 
			
		||||
								subcomponent: AssetsUpload,
 | 
			
		||||
								prop: 'uploadedAssets',
 | 
			
		||||
								default: [],
 | 
			
		||||
								bind: {
 | 
			
		||||
									'is-pic-mode': false,
 | 
			
		||||
								},
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					],
 | 
			
		||||
					[
 | 
			
		||||
						{
 | 
			
		||||
							assetUpload: true,
 | 
			
		||||
							key: 'eq-pics', // 用于区分不同的上传组件
 | 
			
		||||
							label: '上传图片',
 | 
			
		||||
							fieldName: 'images',
 | 
			
		||||
							subcomponent: AssetsUpload,
 | 
			
		||||
							// prop: '',
 | 
			
		||||
							// default: [],
 | 
			
		||||
							bind: {
 | 
			
		||||
								'is-pic-mode': true,
 | 
			
		||||
						],
 | 
			
		||||
						[
 | 
			
		||||
							{
 | 
			
		||||
								assetUpload: true,
 | 
			
		||||
								key: 'eq-pics', // 用于区分不同的上传组件
 | 
			
		||||
								label: '上传图片',
 | 
			
		||||
								fieldName: 'images',
 | 
			
		||||
								subcomponent: AssetsUpload,
 | 
			
		||||
								// prop: '',
 | 
			
		||||
								// default: [],
 | 
			
		||||
								bind: {
 | 
			
		||||
									'is-pic-mode': true,
 | 
			
		||||
								},
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					],
 | 
			
		||||
				]
 | 
			
		||||
						],
 | 
			
		||||
				  ]
 | 
			
		||||
				: this.rows;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
@@ -512,7 +570,8 @@ export default {
 | 
			
		||||
				spec: undefined,
 | 
			
		||||
				description: undefined,
 | 
			
		||||
				remark: undefined,
 | 
			
		||||
				files: []
 | 
			
		||||
				files: [],
 | 
			
		||||
				files2: [],
 | 
			
		||||
			};
 | 
			
		||||
			this.resetForm('form');
 | 
			
		||||
		},
 | 
			
		||||
@@ -540,9 +599,12 @@ export default {
 | 
			
		||||
				if (!valid) {
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
				const payload = Object.assign({}, this.form);
 | 
			
		||||
				payload.files = [...payload.files, ...payload.files2];
 | 
			
		||||
				delete payload.files2;
 | 
			
		||||
				// 修改的提交
 | 
			
		||||
				if (this.form.id != null) {
 | 
			
		||||
					updateEquipment(this.form).then((response) => {
 | 
			
		||||
					updateEquipment(payload).then((response) => {
 | 
			
		||||
						this.$modal.msgSuccess('修改成功');
 | 
			
		||||
						this.open = false;
 | 
			
		||||
						this.getList();
 | 
			
		||||
@@ -550,7 +612,7 @@ export default {
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
				// 添加的提交
 | 
			
		||||
				createEquipment(this.form).then((response) => {
 | 
			
		||||
				createEquipment(payload).then((response) => {
 | 
			
		||||
					this.$modal.msgSuccess('新增成功');
 | 
			
		||||
					this.open = false;
 | 
			
		||||
					this.getList();
 | 
			
		||||
@@ -569,7 +631,7 @@ export default {
 | 
			
		||||
					this.getList();
 | 
			
		||||
					this.$modal.msgSuccess('删除成功');
 | 
			
		||||
				})
 | 
			
		||||
				.catch(() => { });
 | 
			
		||||
				.catch(() => {});
 | 
			
		||||
		},
 | 
			
		||||
		/** 导出按钮操作 */
 | 
			
		||||
		handleExport() {
 | 
			
		||||
@@ -587,7 +649,7 @@ export default {
 | 
			
		||||
					this.$download.excel(response, '设备.xls');
 | 
			
		||||
					this.exportLoading = false;
 | 
			
		||||
				})
 | 
			
		||||
				.catch(() => { });
 | 
			
		||||
				.catch(() => {});
 | 
			
		||||
		},
 | 
			
		||||
		// 查看详情
 | 
			
		||||
		viewDetail(id) {
 | 
			
		||||
 
 | 
			
		||||
@@ -21,18 +21,15 @@ export default {
 | 
			
		||||
			chart: null,
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	// watch: {
 | 
			
		||||
	// 	list: {
 | 
			
		||||
	// 		handler(listdata) {
 | 
			
		||||
	// 			if (listdata && listdata.length) {
 | 
			
		||||
	// 				console.log('[linechart] list changed', listdata);
 | 
			
		||||
	// 				const option = this.handleList(listdata);
 | 
			
		||||
	// 				this.setOption(option);
 | 
			
		||||
	// 			}
 | 
			
		||||
	// 		},
 | 
			
		||||
	// 		immediate: true,
 | 
			
		||||
	// 	},
 | 
			
		||||
	// },
 | 
			
		||||
	watch: {
 | 
			
		||||
		list: {
 | 
			
		||||
			handler(listdata) {
 | 
			
		||||
				this.setOption();
 | 
			
		||||
			},
 | 
			
		||||
			immediate: true,
 | 
			
		||||
			deep: true,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		option() {
 | 
			
		||||
			const opt = [];
 | 
			
		||||
@@ -55,7 +52,7 @@ export default {
 | 
			
		||||
					},
 | 
			
		||||
					formatter: (params) => {
 | 
			
		||||
						const name = params[0].name;
 | 
			
		||||
						const goodRate = opt.find((item) => item[0] == name)[4];
 | 
			
		||||
						const goodRate = opt.find((item) => item[0] == name)[4] || '0';
 | 
			
		||||
						return `
 | 
			
		||||
							<h1 style="font-size: 18px; letter-spacing: 1px;">${
 | 
			
		||||
								params[0].axisValue
 | 
			
		||||
@@ -109,6 +106,9 @@ export default {
 | 
			
		||||
				xAxis: {
 | 
			
		||||
					type: 'category',
 | 
			
		||||
					axisTick: { show: false },
 | 
			
		||||
					axisLabel: {
 | 
			
		||||
						rotate: 45,
 | 
			
		||||
					},
 | 
			
		||||
					data: opt.map((item) => item[0]),
 | 
			
		||||
				},
 | 
			
		||||
				yAxis: {
 | 
			
		||||
 
 | 
			
		||||
@@ -6,15 +6,15 @@
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="app-container">
 | 
			
		||||
	<div class="app-container" style="flex: 1; height: 1px; display: flex; flex-direction: column;">
 | 
			
		||||
		<!-- 搜索工作栏 -->
 | 
			
		||||
		<SearchBar
 | 
			
		||||
			:formConfigs="searchBarFormConfig"
 | 
			
		||||
			ref="search-bar"
 | 
			
		||||
			@headBtnClick="handleSearchBarBtnClick" />
 | 
			
		||||
 | 
			
		||||
		<el-row>
 | 
			
		||||
			<el-col class="custom-tabs">
 | 
			
		||||
		<el-row type="flex" style="flex: 1;">
 | 
			
		||||
			<el-col class="custom-tabs" style="flex: 1;">
 | 
			
		||||
				<el-tabs
 | 
			
		||||
					v-model="activeName"
 | 
			
		||||
					:stretch="true"
 | 
			
		||||
@@ -32,7 +32,7 @@
 | 
			
		||||
						<div
 | 
			
		||||
							v-if="activeName == 'graph'"
 | 
			
		||||
							class="graph"
 | 
			
		||||
							style="height: 40vh; display: flex; flex-direction: column">
 | 
			
		||||
							style="height: 100%; display: flex; flex-direction: column">
 | 
			
		||||
							<div class="blue-title">各设备加工数量</div>
 | 
			
		||||
							<LineChart v-if="list && list.length" :list="list" />
 | 
			
		||||
							<div v-else class="no-data-bg"></div>
 | 
			
		||||
@@ -63,13 +63,13 @@ export default {
 | 
			
		||||
			activeName: 'table', // defaults to 'table'
 | 
			
		||||
			searchBarFormConfig: [
 | 
			
		||||
				// 产品
 | 
			
		||||
				{
 | 
			
		||||
					__index: 'product',
 | 
			
		||||
					type: 'select',
 | 
			
		||||
					label: '产品',
 | 
			
		||||
					placeholder: '请选择产品',
 | 
			
		||||
					param: 'productId',
 | 
			
		||||
				},
 | 
			
		||||
				// {
 | 
			
		||||
				// 	__index: 'product',
 | 
			
		||||
				// 	type: 'select',
 | 
			
		||||
				// 	label: '产品',
 | 
			
		||||
				// 	placeholder: '请选择产品',
 | 
			
		||||
				// 	param: 'productId',
 | 
			
		||||
				// },
 | 
			
		||||
				// 产线
 | 
			
		||||
				{
 | 
			
		||||
					__index: 'line',
 | 
			
		||||
@@ -156,17 +156,17 @@ export default {
 | 
			
		||||
				{
 | 
			
		||||
					// width: 160,
 | 
			
		||||
					prop: 'inQuantity',
 | 
			
		||||
					label: '进片数量',
 | 
			
		||||
					label: '加工数量',
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					// width: 160,
 | 
			
		||||
					prop: 'outQuantity',
 | 
			
		||||
					label: '出片数量',
 | 
			
		||||
					label: '合格数量',
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					// width: 160,
 | 
			
		||||
					prop: 'nokQuantity',
 | 
			
		||||
					label: '破损/不合格数',
 | 
			
		||||
					label: '不合格数量',
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					// width: 160,
 | 
			
		||||
@@ -377,6 +377,9 @@ export default {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:deep(.custom-tabs) {
 | 
			
		||||
	.el-tabs {
 | 
			
		||||
		height: 100%;
 | 
			
		||||
	}
 | 
			
		||||
	.el-tabs__header {
 | 
			
		||||
		margin-bottom: 8px;
 | 
			
		||||
		display: inline-block;
 | 
			
		||||
@@ -389,6 +392,14 @@ export default {
 | 
			
		||||
		line-height: 36px !important;
 | 
			
		||||
		height: 36px;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.el-tabs__content {
 | 
			
		||||
		height: calc(100% - 48px);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#pane-graph {
 | 
			
		||||
		height: 100%;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.blue-title {
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,8 @@
 | 
			
		||||
							:dataForm="form"
 | 
			
		||||
							:rows="formRows" /> -->
 | 
			
		||||
 | 
			
		||||
						<el-row v-if="mode.includes('detail')" style="margin-bottom: 24px">
 | 
			
		||||
						<!-- <el-row v-if="mode.includes('detail')" style="margin-bottom: 24px"> -->
 | 
			
		||||
						<el-row style="margin-bottom: 24px">
 | 
			
		||||
							<el-col :span="8">
 | 
			
		||||
								<div
 | 
			
		||||
									class="title"
 | 
			
		||||
@@ -62,7 +63,7 @@
 | 
			
		||||
								</div>
 | 
			
		||||
							</el-col>
 | 
			
		||||
						</el-row>
 | 
			
		||||
						<el-row v-else style="margin-bottom: 24px" :gutter="20">
 | 
			
		||||
						<!-- <el-row v-else style="margin-bottom: 24px" :gutter="20">
 | 
			
		||||
							<el-form ref="form" :model="form">
 | 
			
		||||
								<el-col :span="8">
 | 
			
		||||
									<el-form-item
 | 
			
		||||
@@ -85,7 +86,7 @@
 | 
			
		||||
									</el-form-item>
 | 
			
		||||
								</el-col>
 | 
			
		||||
							</el-form>
 | 
			
		||||
						</el-row>
 | 
			
		||||
						</el-row> -->
 | 
			
		||||
					</div>
 | 
			
		||||
 | 
			
		||||
					<div
 | 
			
		||||
@@ -132,8 +133,8 @@
 | 
			
		||||
				<el-button
 | 
			
		||||
					type="primary"
 | 
			
		||||
					v-if="!mode.includes('detail')"
 | 
			
		||||
					@click="handleSave">
 | 
			
		||||
					保存
 | 
			
		||||
					@click="handleCancel">
 | 
			
		||||
					确定
 | 
			
		||||
				</el-button>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ export default {
 | 
			
		||||
				color: ['#288AFF'],
 | 
			
		||||
				grid: {
 | 
			
		||||
					top: 64,
 | 
			
		||||
					left: 56,
 | 
			
		||||
					left: '8%',
 | 
			
		||||
					right: 64,
 | 
			
		||||
					bottom: 56,
 | 
			
		||||
				},
 | 
			
		||||
 
 | 
			
		||||
@@ -67,15 +67,20 @@
 | 
			
		||||
			class="app-container equipment-process-amount"
 | 
			
		||||
			style="flex: 1; border-radius: 8px; background: #fff">
 | 
			
		||||
			<!-- main area  -->
 | 
			
		||||
			<div class="main-content" style="display: flex; flex-direction: column">
 | 
			
		||||
			<div
 | 
			
		||||
				class="main-content"
 | 
			
		||||
				style="height: 100%; display: flex; flex-direction: column">
 | 
			
		||||
				<SearchBar
 | 
			
		||||
					:formConfigs="searchBarFormConfig"
 | 
			
		||||
					ref="search-bar"
 | 
			
		||||
					@headBtnClick="handleSearchBarBtnClick" />
 | 
			
		||||
 | 
			
		||||
				<el-row>
 | 
			
		||||
					<el-col class="custom-tabs">
 | 
			
		||||
						<el-tabs v-model="activeName" @tab-click="handleTabClick">
 | 
			
		||||
				<el-row style="flex: 1">
 | 
			
		||||
					<el-col class="custom-tabs" style="height: 100%">
 | 
			
		||||
						<el-tabs
 | 
			
		||||
							v-model="activeName"
 | 
			
		||||
							@tab-click="handleTabClick"
 | 
			
		||||
							style="height: 100%">
 | 
			
		||||
							<el-tab-pane :label="'\u2002数据列表\u2002'" name="table">
 | 
			
		||||
								<base-table
 | 
			
		||||
									v-if="mode == 'table'"
 | 
			
		||||
@@ -93,7 +98,9 @@
 | 
			
		||||
								</base-table>
 | 
			
		||||
							</el-tab-pane>
 | 
			
		||||
							<el-tab-pane :label="'\u3000柱状图\u3000'" name="graph">
 | 
			
		||||
								<div class="graph" style="height: 56vh">
 | 
			
		||||
								<div
 | 
			
		||||
									class="graph"
 | 
			
		||||
									style="height: 100%;">
 | 
			
		||||
									<!-- graph  -->
 | 
			
		||||
									<Graph
 | 
			
		||||
										v-if="list.length"
 | 
			
		||||
@@ -546,6 +553,13 @@ li {
 | 
			
		||||
	.el-tree-node__content {
 | 
			
		||||
	padding: 8px 24px !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.custom-tabs >>> .el-tabs__content {
 | 
			
		||||
	height: calc(100% - 42px);
 | 
			
		||||
}
 | 
			
		||||
.custom-tabs >>> .el-tab-pane {
 | 
			
		||||
	height: 100%;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user