From 63d520e224802bce74dfda4d526061453682b5fc Mon Sep 17 00:00:00 2001
From: licp <lichunping@guanfang.com.cn>
Date: 星期四, 19 十二月 2024 11:09:23 +0800
Subject: [PATCH] 完成客户满意度搬迁

---
 src/components/do/a8-customer-satisfaction/formDialog.vue |  286 +++++++++++++++
 src/components/caorui/ZTTable/index.vue                   |  303 +++++++++++++++
 src/components/caorui/TableCard/index.vue                 |   68 +++
 src/assets/api/controller.js                              |   12 
 src/components/view/a8-customer-satisfaction.vue          |  440 +++++++++++++++++++++++
 5 files changed, 1,109 insertions(+), 0 deletions(-)

diff --git a/src/assets/api/controller.js b/src/assets/api/controller.js
index 3d05fd0..f96c4b6 100644
--- a/src/assets/api/controller.js
+++ b/src/assets/api/controller.js
@@ -42,6 +42,7 @@
     manageRecordCancel,
     manageRecordAudit,
     personnel,
+    clientSatisfaction,
   }
 }
 
@@ -545,3 +546,14 @@
 const personnel = {
   selectCNSAPersonTree: '/personBasicInfo/selectCNSAPersonTree', // 鏌ヨCNAS浜哄憳渚ц竟鏍�
 }
+
+// 8.3 瀹㈡埛婊℃剰搴﹁皟鏌�
+const clientSatisfaction = {
+  pageClientSatisfaction:'/clientSatisfaction/pageClientSatisfaction', // 瀹㈡埛婊℃剰搴﹁皟鏌ュ垪琛�
+  addClientSatisfaction:'/clientSatisfaction/addClientSatisfaction', // 鏂板瀹㈡埛婊℃剰搴﹁皟鏌�
+  updateClientSatisfaction:'/clientSatisfaction/updateClientSatisfaction', // 淇敼鏂板瀹㈡埛婊℃剰搴﹁皟鏌�
+  delClientSatisfaction:'/clientSatisfaction/delClientSatisfaction', // 鍒犻櫎鏂板瀹㈡埛婊℃剰搴﹁皟鏌�
+  pageAnalyseFile:'/clientSatisfaction/pageAnalyseFile', // 鏌ヨ瀹㈡埛鍒嗘瀽闄勪欢
+  uploadAnalyseFile:'/clientSatisfaction/uploadAnalyseFile', // 鏂板瀹㈡埛鍒嗘瀽闄勪欢
+  delAnalyseFile:'/clientSatisfaction/delAnalyseFile', // 鍒犻櫎瀹㈡埛鍒嗘瀽闄勪欢
+}
diff --git a/src/components/caorui/TableCard/index.vue b/src/components/caorui/TableCard/index.vue
new file mode 100644
index 0000000..64f8889
--- /dev/null
+++ b/src/components/caorui/TableCard/index.vue
@@ -0,0 +1,68 @@
+<template>
+  <div class="table_card">
+    <div v-if="showTitle" class="title">
+      <span style="font-weight: bold">{{ title }}</span>
+    </div>
+    <div v-if="showForm" class="table_card_form">
+      <slot name="form"></slot>
+    </div>
+    <div>
+      <slot name="table"></slot>
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    title: {
+      type: String,
+      default: '鏍囬'
+    },
+    showTitle: {
+      type: Boolean,
+      default: true
+    },
+    showForm: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {};
+  }
+};
+</script>
+<style scoped>
+.table_card {
+  text-align: left;
+}
+
+.title {
+  position: relative;
+  font-size: 18px;
+  color: #333;
+  font-weight: 400;
+  padding-left: 10px;
+  margin-left: 15px;
+}
+
+.title::before {
+  position: absolute;
+  left: 0;
+  top: 4px;
+  content: '';
+  width: 4px;
+  height: 18px;
+  background-color: #3A7BFA;
+  border-radius: 2px;
+}
+
+.table_card_form {
+  display: flex;
+  justify-content: space-between;
+  height: 34px;
+  padding: 0 15px;
+  margin-bottom: 10px;
+}
+
+</style>
diff --git a/src/components/caorui/ZTTable/index.vue b/src/components/caorui/ZTTable/index.vue
new file mode 100644
index 0000000..17864dd
--- /dev/null
+++ b/src/components/caorui/ZTTable/index.vue
@@ -0,0 +1,303 @@
+<!--
+ * @FileDescription: 琛ㄦ牸缁勪欢
+ * @Author: 鏇圭澘
+ * @Date: 2024/09/29
+ * @LastEditors: licp lichunping@guanfang.com.cn
+ * @LastEditTime: 2024-12-03 11:05:06
+ -->
+<template>
+  <div>
+    <!-- 琛ㄦ牸 -->
+    <el-table 
+        ref="multipleTable" 
+        v-loading="tableLoading" 
+        :border="border" 
+        :data="tableData"
+        :header-cell-style="{ background: '#0e3372', color: '#cccccc' }" 
+        :height="height"
+        :highlight-current-row="highlightCurrentRow" 
+        :row-class-name="rowClassName"
+        :row-style="rowStyle"
+        :row-key="rowKey"
+        stripe
+        style="width: 100%; " 
+        tooltip-effect="dark"
+        @row-click="rowClick"
+        @current-change="currentChange"
+        @selection-change="handleSelectionChange"
+      >
+      <template v-if="isSelection">
+        <el-table-column type="selection" width="55" />
+      </template>
+      <template>
+        <el-table-column align="center" label="搴忓彿" type="index" width="60" />
+      </template>
+
+      <template v-for="(item, index) in column">
+        <el-table-column :column-key="item.columnKey" :filter-method="item.filterHandler"
+                         :filter-multiple="item.filterMultiple" :filtered-value="item.filteredValue"
+                         :filters="item.filters" :fixed="item.fixed" :label="item.label"
+                         :min-width="item.minWidth" :prop="item.prop"
+                         :show-overflow-tooltip="item.showOverflowTooltip"
+                         :sortable="item.sortable ? true : false" :type="item.type" :width="item.width"
+                         align="center">
+
+          <!-- <div class="123" v-if="item.type == ''"> -->
+          <template v-if="item.hasOwnProperty('colunmTemplate')" :slot="item.colunmTemplate"
+                    slot-scope="scope">
+            <slot v-if="item.theadSlot" :index="index" :name="item.theadSlot" :row="scope.row" />
+          </template>
+
+          <template slot-scope="scope">
+            <!-- 鎻掓Ы -->
+            <div v-if="item.dataType == 'slot'">
+              <slot v-if="item.slot" :index="scope.$index" :name="item.slot" :row="scope.row" />
+            </div>
+
+
+            <!-- 杩涘害鏉� -->
+            <div v-else-if="item.dataType == 'progress'">
+              <el-progress :percentage="Number(scope.row[item.prop])" />
+            </div>
+
+            <!-- tag -->
+            <div v-else-if="item.dataType == 'tag'">
+              <el-tag v-if="typeof dataTypeFn(scope.row[item.prop], item.formatData) == 'string'"
+                      :title="scope.row[item.prop] | formatters(item.formatData)"
+                      :type="formatType(scope.row[item.prop], item.formatType)">{{ scope.row[item.prop] | formatters(item.formatData) }}</el-tag>
+              <el-tag v-for="(tag, index) in dataTypeFn(scope.row[item.prop], item.formatData)"
+                      v-else-if="typeof dataTypeFn(scope.row[item.prop], item.formatData) == 'object'"
+                      :key="index" :title="scope.row[item.prop] | formatters(item.formatData)"
+                      :type="formatType(tag, item.formatType)">{{ item.tagGroup ? tag[item.tagGroup.label] ? tag[item.tagGroup.label] : tag : tag }}</el-tag>
+              <el-tag v-else :title="scope.row[item.prop] | formatters(item.formatData)"
+                      :type="formatType(scope.row[item.prop], item.formatType)">{{ scope.row[item.prop] | formatters(item.formatData) }}</el-tag>
+            </div>
+
+            <!-- 鎸夐挳 -->
+            <div v-else-if="item.dataType == 'action'">
+              <template v-for="(o, key) in item.operation">
+                <el-button
+                    v-if="o.type!='upload'"
+                    v-show="o.showHide ? o.showHide(scope.row) : true"
+                    :disabled="o.disabled ? o.disabled(scope.row) : false"
+                    :icon="o.icon | iconFn(scope.row)"
+                    :plain="o.plain" :size="o.size"
+                    :style="{ 'color': o.color }" 
+                    :type="o.type | typeFn(scope.row)"
+                    @click="o.clickFun(scope.row)">
+                  {{ o.name }}
+                </el-button>
+                <el-upload
+                  action="#"
+                  :on-change="(file, fileList)=>o.clickFun(scope.row,file, fileList)"
+                  :multiple="o.multiple?o.multiple:false"
+                  :limit="o.limit?o.limit:1"
+                  :disabled="o.disabled ? o.disabled(scope.row) : false"
+                  :accept="o.accept?o.accept:'.jpg,.jpeg,.png,.gif,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.zip,.rar'"
+                  v-if="o.type=='upload'" style="display: inline-block;width: 50px;"
+                  v-show="o.showHide ? o.showHide(scope.row) : true"
+                  :auto-upload="false"
+                  :on-exceed="onExceed"
+                  :show-file-list="false">
+                  <el-button :size="o.size?o.size:'small'" type="text" :disabled="o.disabled ? o.disabled(scope.row) : false">{{o.name}}</el-button>
+                </el-upload>
+              </template>
+            </div>
+
+            <!--  -->
+
+            <!-- 榛樿绾睍绀烘暟鎹� -->
+            <div v-else>
+              <span v-if="!item.formatData">{{ scope.row[item.prop] }}</span>
+              <span v-else>{{ scope.row[item.prop] | formatters(item.formatData) }}</span>
+            </div>
+
+          </template>
+
+          <!-- </div>   -->
+
+        </el-table-column>
+      </template>
+    </el-table>
+  </div>
+</template>
+
+<script>
+// 娉細浠ヤ笅鏄墍鏈夐厤缃」锛屽叾涓渶甯镐娇鐢ㄧ殑灏辨槸label銆亀idth銆乸rop銆乨ataType銆乻lot
+// label 锛氬垪鍚嶏紝灏辨槸琛ㄥご涓婄殑鏍囩鍙粈涔堜簺浠�涔堬紝绫诲瀷 string
+// width锛氳鍒楀搴︼紝 string
+// prop锛�  table缁戝畾鏁版嵁瀛楁 string,杩欎竴鍒楄灞曠ず鍝釜tableData閲岄潰鐨勫瓧娈靛氨鍐欏摢涓瓧娈�
+// dataType锛�  鍐呯疆澶氫釜鍩烘湰鐨別lement缁勪欢鍙緵鐩存帴浣跨敤 string
+// slot  褰揱dataType`涓篳slot`鏃跺繀甯﹀弬鏁帮紝鍙傛暟鍊间负鎻掓Ы鐨� `slot` 鍊� string锛屽叿浣撲娇鐢ㄦ柟娉曡鐪嬩笅闈㈢殑绗�4鐐箂lot鎻掓Ы鐨勪娇鐢�
+// fixed锛氬垪鏄惁鍥哄畾鍦ㄥ乏渚ф垨鑰呭彸渚э紝true 琛ㄧず鍥哄畾鍦ㄥ乏渚� string, boolean
+// sortable 瀵瑰簲鍒楁槸鍚﹀彲浠ユ帓搴� boolean, string
+// filters 鏁版嵁杩囨护鐨勯�夐」锛屾暟缁勬牸寮忥紝鏁扮粍涓殑鍏冪礌闇�瑕佹湁 text 鍜� value 灞炴�с�侫rray
+// columnKey 锛歝olumn 鐨� key锛屽鏋滈渶瑕佷娇鐢� filter-change 浜嬩欢锛屽垯闇�瑕佹灞炴�ф爣璇嗘槸鍝釜 column 鐨勭瓫閫夋潯浠�
+// filteredValue  閫変腑鐨勬暟鎹繃婊ら」锛屽鏋滈渶瑕佽嚜瀹氫箟琛ㄥご杩囨护鐨勬覆鏌撴柟寮忥紝鍙兘浼氶渶瑕佹灞炴�с��
+// filterMultiple  鏁版嵁杩囨护鐨勯�夐」鏄惁澶氶��
+// minWidth 瀵瑰簲鍒楃殑鏈�灏忓搴︼紝涓� width 鐨勫尯鍒槸 width 鏄浐瀹氱殑锛宮in-width 浼氭妸鍓╀綑瀹藉害鎸夋瘮渚嬪垎閰嶇粰璁剧疆浜� min-width 鐨勫垪 string
+// formatData  瀵规暟鎹繘琛屾暟鎹鐞嗭紝鎺ュ彈涓�涓洖璋冨嚱鏁� (params?: {prop}) => {}
+// formatType  褰� `dataType`涓� `tag`鏃讹紝瀵规爣绛鹃鑹茶缃� (params?: {prop}) => { return 'danger'| 'success'... }`
+// operation 褰� `dataType` 涓� `option`鏃讹紝瀵规寜閽殑 閰嶇疆锛屽叿浣撻厤缃」浠ヤ笅鍥句负鍑唎bject
+// tagGroup 褰� `dataType`涓� `tag`鏃讹紝缁戝畾鏁版嵁闆嗗瓧娈垫樉绀哄悕绉� object
+/**
+ * 鎻掓Ы鐨勪娇鐢ㄦ柟娉�:
+ */
+/* <div
+     slot="protocolSlot"
+     slot-scope="scope"
+    >
+        <span>{{ scope.row.protocol }}</span>
+    </div>
+*/
+/**
+ * 浣跨敤formatData杩涜鏁版嵁澶勭悊
+ */
+//  {
+//           type: '',
+//           label: '鍚敤鐘舵��',
+//           prop: 'is_active',
+//           formatData: (item) => {
+//             const str = item == true ? '宸插惎鐢�' : '鏈惎鐢�'
+//             return str
+//           }
+//         },
+/**
+ * operation閰嶇疆
+ */
+//  operation閰嶇疆涓昏鏄潵鐢ㄤ簬琛ㄦ牸閲岄潰鐨勬搷浣滈偅涓�鍒楋紝閫氬父灏变細鏈夊緢澶氭寜閽紝鏈変互涓嬪弬鏁帮細
+// name锛氭寜閽悕绉帮紝string
+// type锛氭寜閽被鍨嬶紝`string` | `danger | success`锛屼互elementUi 鍙傛暟涓哄噯
+// size锛氭寜閽ぇ灏忥紝浠lementUi 鍙傛暟涓哄噯
+// icon锛氭寜閽笂鐨刬con锛屼互elementUi 鍙傛暟涓哄噯
+// plain锛氭寜elementUi 鏂囨。涓哄噯
+// clickFun锛氭寜閽殑鍥炶皟鍑芥暟
+export default {
+  name: 'ZTTable',
+  filters: {
+    iconFn(val, row) {
+      if (typeof (val) === 'function') {
+        return val(row);
+      } else return val;
+    },
+    typeFn(val, row) {
+      // console.log(val, row, '11111111');
+      if (typeof (val) === 'function') {
+        return val(row);
+      } else return val;
+    },
+    describeConts(val, describeCont) {
+      if (typeof (describeCont) === 'function') {
+        return describeCont(val);
+      } else return val;
+    },
+    formatters(val, format) {
+      if (typeof (format) === 'function') {
+        return format(val);
+      } else return val;
+    }
+  },
+  props: {
+    isSelection: {
+      type: Boolean,
+      default: false
+    },
+    height: {
+      type: String,
+      default: null
+    },
+    tableLoading: {
+      type: Boolean,
+      default: false
+    },
+    handleSelectionChange: {
+      type: Function,
+      default: () => {
+        return () => {
+        };
+      }
+    },
+    rowClick: {
+      type: Function,
+      default: () => {
+        return () => {
+        };
+      }
+    },
+    currentChange: {
+      type: Function,
+      default: () => {
+        return () => {
+        };
+      }
+    },
+    border: {
+      type: Boolean,
+      default: true
+    },
+    highlightCurrentRow: {
+      type: Boolean,
+      default: false
+    },
+    headerCellStyle: {
+      type: Object,
+      default: () => {
+        return {};
+      }
+    },
+    column: {
+      type: Array,
+      default() {
+        return [];
+      }
+    },
+    rowClassName: {
+      type: Function,
+      default: () => {
+
+      }
+    },
+    rowStyle: {
+      type: Function,
+      default: () => {
+
+      }
+    },
+    tableData: {
+      type: Array,
+      default() {
+        return [];
+      }
+    },
+    rowKey: {
+      type: String,
+      default: undefined
+    }
+  },
+
+  methods: {
+    formatType(val, format) {
+      if (typeof (format) === 'function') {
+        return format(val);
+      } else return '';
+    },
+    dataTypeFn(val, format) {
+      if (typeof (format) === 'function') {
+        return format(val);
+      } else return val;
+    },
+    setCurrent(row) {
+      this.$refs.multipleTable.setCurrentRow();
+    },
+    onExceed(){
+      this.$message.warning('瓒呭嚭鏂囦欢涓暟');
+    }
+  }
+};
+</script>
+
+<style scoped>
+.el-table >>> .el-table__empty-text {
+  text-align: center
+}
+</style>
diff --git a/src/components/do/a8-customer-satisfaction/formDialog.vue b/src/components/do/a8-customer-satisfaction/formDialog.vue
new file mode 100644
index 0000000..f8ba0a9
--- /dev/null
+++ b/src/components/do/a8-customer-satisfaction/formDialog.vue
@@ -0,0 +1,286 @@
+<template>
+  <div>
+    <el-dialog :close-on-click-modal="false" :close-on-press-escape="false"
+               :visible.sync="formDia"
+               title="瀹㈡埛婊℃剰搴﹁皟鏌ヨ〃"
+               width="70%"
+               @close="closeFormDia">
+      <table border="1" cellspacing="10" class="tables">
+        <tr>
+          <td class="td-title">
+            <p>鍗曚綅鍚嶇О锛�</p>
+          </td>
+          <td class="td-info" colspan="2">
+            <el-input v-model="form.unitName"
+                      placeholder="璇疯緭鍏ュ唴瀹�"
+                      size="small">
+            </el-input>
+          </td>
+          <td class="td-title">
+            <p>鏃ユ湡锛�</p>
+          </td>
+          <td class="td-info" colspan="2">
+            <el-date-picker
+              v-model="form.fillDate"
+              format="yyyy-MM-dd"
+              placeholder="閫夋嫨鏃ユ湡"
+              size="small"
+              type="date"
+              value-format="yyyy-MM-dd">
+            </el-date-picker>
+          </td>
+        </tr>
+        <tr>
+          <td class="td-title">
+            <p>濮撳悕锛�</p>
+          </td>
+          <td class="td-info">
+            <el-input v-model="form.userName"
+                      placeholder="璇疯緭鍏ュ唴瀹�"
+                      size="small">
+            </el-input>
+          </td>
+          <td class="td-title">
+            <p>閮ㄩ棬锛�</p>
+          </td>
+          <td class="td-info">
+            <el-input v-model="form.department"
+                      placeholder="璇疯緭鍏ュ唴瀹�"
+                      size="small">
+            </el-input>
+          </td>
+          <td class="td-title">
+            <p>鑱旂郴鐢佃瘽锛�</p>
+          </td>
+          <td class="td-info">
+            <el-input v-model="form.contactNumber"
+                      placeholder="璇疯緭鍏ュ唴瀹�"
+                      size="small">
+            </el-input>
+          </td>
+        </tr>
+        <tr>
+          <td class="td-title">
+            <p>鏈嶅姟鎬佸害锛�</p>
+          </td>
+          <td class="td-info" colspan="2">
+            <el-radio-group v-model="form.serviceAttitude" v-removeAriaHidden>
+              <el-radio :label="0">婊℃剰</el-radio>
+              <el-radio :label="1">涓�鑸�</el-radio>
+              <el-radio :label="2">涓嶆弧鎰�</el-radio>
+            </el-radio-group>
+          </td>
+          <td class="td-title">
+            <p>寤鸿锛�</p>
+          </td>
+          <td class="td-info" colspan="2">
+            <el-input v-model="form.serviceAttitudeSuggestion"
+                      placeholder="璇疯緭鍏ュ唴瀹�"
+                      size="small">
+            </el-input>
+          </td>
+        </tr>
+        <tr>
+          <td class="td-title">
+            <p>鎶�鏈兘鍔涳細</p>
+          </td>
+          <td class="td-info" colspan="2">
+            <el-radio-group v-model="form.technicalCompetence" v-removeAriaHidden>
+              <el-radio :label="0">婊℃剰</el-radio>
+              <el-radio :label="1">涓�鑸�</el-radio>
+              <el-radio :label="2">涓嶆弧鎰�</el-radio>
+            </el-radio-group>
+          </td>
+          <td class="td-title">
+            <p>寤鸿锛�</p>
+          </td>
+          <td class="td-info" colspan="2">
+            <el-input v-model="form.technicalCompetenceSuggestion"
+                      placeholder="璇疯緭鍏ュ唴瀹�"
+                      size="small">
+            </el-input>
+          </td>
+        </tr>
+        <tr>
+          <td class="td-title">
+            <p>妫�娴嬪伐浣滐細</p>
+          </td>
+          <td class="td-info" colspan="2">
+            <el-radio-group v-model="form.inspectionWork" v-removeAriaHidden>
+              <el-radio :label="0">婊℃剰</el-radio>
+              <el-radio :label="1">涓�鑸�</el-radio>
+              <el-radio :label="2">涓嶆弧鎰�</el-radio>
+            </el-radio-group>
+          </td>
+          <td class="td-title">
+            <p>寤鸿锛�</p>
+          </td>
+          <td class="td-info" colspan="2">
+            <el-input v-model="form.inspectionWorkSuggestion"
+                      placeholder="璇疯緭鍏ュ唴瀹�"
+                      size="small">
+            </el-input>
+          </td>
+        </tr>
+        <tr>
+          <td class="td-title">
+            <p>鏀惰垂鍚堢悊鎬э細</p>
+          </td>
+          <td class="td-info" colspan="2">
+            <el-radio-group v-model="form.reasonableFees" v-removeAriaHidden>
+              <el-radio :label="0">婊℃剰</el-radio>
+              <el-radio :label="1">涓�鑸�</el-radio>
+              <el-radio :label="2">涓嶆弧鎰�</el-radio>
+            </el-radio-group>
+          </td>
+          <td class="td-title">
+            <p>寤鸿锛�</p>
+          </td>
+          <td class="td-info" colspan="2">
+            <el-input v-model="form.reasonableFeesSuggestion"
+                      placeholder="璇疯緭鍏ュ唴瀹�"
+                      size="small">
+            </el-input>
+          </td>
+        </tr>
+        <tr>
+          <td class="td-title">
+            <p>鎮ㄥ鎴戜滑鐨勫笇鏈涳細</p>
+          </td>
+          <td class="td-info" colspan="5">
+            <el-input v-model="form.remark"
+                      :rows="4"
+                      placeholder="璇疯緭鍏ュ唴瀹�"
+                      size="small"
+                      type="textarea">
+            </el-input>
+          </td>
+        </tr>
+      </table>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="closeFormDia">鍙� 娑�</el-button>
+        <el-button :loading="editLoad" type="primary" @click="handleEdit">鎻� 浜�</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'formDialog',
+  // import 寮曞叆鐨勭粍浠堕渶瑕佹敞鍏ュ埌瀵硅薄涓墠鑳戒娇鐢�
+  components: {},
+  data() {
+    // 杩欓噷瀛樻斁鏁版嵁
+    return {
+      formDia: false,
+      form: {
+        unitName: '',
+        fillDate: '',
+        userName: '',
+        department: '',
+        contactNumber: '',
+        serviceAttitude: '',
+        technicalCompetence: '',
+        technicalCompetenceSuggestion: '',
+        inspectionWork: '',
+        inspectionWorkSuggestion: '',
+        reasonableFees: '',
+        reasonableFeesSuggestion: '',
+        remark: '',
+        clientSatisfactionId: '',
+      },
+      operationType: '',
+      editLoad: false,
+
+    };
+  },
+  // 鏂规硶闆嗗悎
+  methods: {
+    openDia (type, row) {
+      this.formDia = true;
+      this.operationType = type
+      if (this.operationType === 'edit') {
+        this.form = {...row}
+      }
+    },
+    handleEdit () {
+      if (!this.form.unitName	) {
+        this.$message.warning('璇峰~鍐欏崟浣嶅悕绉�')
+        return
+      }
+      if (!this.form.department	) {
+        this.$message.warning('璇峰~鍐欓儴闂�')
+        return
+      }
+      this.editLoad = true
+      if (this.operationType === 'add') {
+        this.$axios.post(this.$api.clientSatisfaction.addClientSatisfaction, this.form, {
+          headers: {
+            "Content-Type": "application/json"
+          },
+          noQs: true
+        }).then(res => {
+          this.editLoad = false
+          if (res.code === 201) return
+          this.$message.success('鎻愪氦鎴愬姛')
+          this.closeFormDia()
+        }).catch(err => {
+          console.log('err---', err);
+          this.editLoad = false
+        })
+      } else {
+        this.$axios.post(this.$api.clientSatisfaction.updateClientSatisfaction, this.form, {
+          headers: {
+            "Content-Type": "application/json"
+          },
+          noQs: true
+        }).then(res => {
+          this.editLoad = false
+          if (res.code === 201) return
+          this.$message.success('鎻愪氦鎴愬姛')
+          this.closeFormDia()
+        }).catch(err => {
+          console.log('err---', err);
+          this.editLoad = false
+        })
+      }
+    },
+    closeFormDia () {
+      this.formDia = false;
+      this.$emit('closeFormDia')
+    },
+  }
+};
+</script>
+
+<style scoped>
+>>>.el-dialog {
+  margin: 10vh auto 50px !important;
+}
+.tables {
+  table-layout: fixed;
+  width: 100%;
+  margin-top: 10px;
+}
+.td-title {
+  height: 40px;
+  width: 170px;
+  text-align: center;
+  font-size: 14px;
+  word-wrap: break-word;
+  white-space: normal;
+  padding: 6px;
+}
+.td-info {
+  padding: 6px;
+}
+.td-info1 {
+  display: inline-block;
+  width: 100%;
+  text-align: left;
+  font-size: 14px;
+  word-wrap: break-word;
+  white-space: normal;
+}
+</style>
diff --git a/src/components/view/a8-customer-satisfaction.vue b/src/components/view/a8-customer-satisfaction.vue
new file mode 100644
index 0000000..11d8c7d
--- /dev/null
+++ b/src/components/view/a8-customer-satisfaction.vue
@@ -0,0 +1,440 @@
+<template>
+  <div>
+    <div>
+      <div class="view-title">
+        <span>瀹㈡埛婊℃剰搴�</span>
+        <span>
+          <el-button v-if="tabIndex === '0'" size="medium" type="primary" @click="openFormDia('add')">鏂� 澧�</el-button>
+          <el-upload v-if="tabIndex === '1'" ref='upload'
+                     :action="action"
+                     :before-upload="beforeUpload" :headers="headers" :on-error="onError"
+                     :on-success="handleSuccessUp" :show-file-list="false" accept='.jpg,.jpeg,.png,.gif,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.zip,.rar'>
+              <el-button :loading="upLoading" size="small" type="primary">瀵煎叆</el-button>
+            </el-upload>
+        </span>
+      </div>
+      <div class="search-background">
+        <span v-if="tabIndex === '0'" class="search-group">
+          <span style="width: 150px">鍗曚綅鍚嶇О锛�</span>
+          <el-input v-model="searchForm.unitName" clearable size="small"></el-input>
+        </span>
+        <span v-if="tabIndex === '1'" class="search-group">
+          <span style="width: 150px">鏂囦欢鍚嶇О锛�</span>
+          <el-input v-model="searchForm1.fileName" clearable size="small"></el-input>
+        </span>
+        <span class="search-group">
+          <el-button size="medium"  @click="resetSearchForm">閲� 缃�</el-button>
+          <el-button size="medium" type="primary" @click="searchList">鏌� 璇�</el-button>
+        </span>
+      </div>
+      <div class="table">
+        <div class="table-tab">
+          <el-radio-group v-model="tabIndex" @change="searchList">
+            <el-radio-button label="0">瀹㈡埛婊℃剰搴�</el-radio-button>
+            <el-radio-button label="1">缁煎悎鍒嗘瀽</el-radio-button>
+          </el-radio-group>
+        </div>
+        <div v-if="tabIndex === '0'">
+          <TableCard :showForm="false" :showTitle="false">
+            <template v-slot:table>
+              <ZTTable
+                :column="tableColumn"
+                :height="'calc(100vh - 27em)'"
+                :table-data="tableData"
+                :table-loading="tableLoading"
+                style="padding: 0 15px;margin-bottom: 16px">
+              </ZTTable>
+            </template>
+          </TableCard>
+          <el-pagination :current-page="1" :page-size="page.size" :page-sizes="[10, 20, 30, 50, 100]"
+                         :total="total" layout="->,total, sizes, prev, pager, next, jumper"
+                         @size-change="handleSizeChange"
+                         @current-change="handleCurrentChange">
+          </el-pagination>
+        </div>
+        <div v-if="tabIndex === '1'">
+          <TableCard :showForm="false" :showTitle="false">
+            <template v-slot:table>
+              <ZTTable
+                :column="tableColumn1"
+                :height="'calc(100vh - 27em)'"
+                :table-data="tableData1"
+                :table-loading="tableLoading1"
+                style="padding: 0 15px;margin-bottom: 16px">
+              </ZTTable>
+            </template>
+          </TableCard>
+          <el-pagination :current-page="1" :page-size="page.size" :page-sizes="[10, 20, 30, 50, 100]"
+                         :total="total1" layout="->,total, sizes, prev, pager, next, jumper"
+                         @size-change="handleSizeChange1"
+                         @current-change="handleCurrentChange1">
+          </el-pagination>
+        </div>
+      </div>
+    </div>
+    <el-dialog
+      :visible.sync="lookDialogVisible"
+      fullscreen
+      title="鏌ョ湅闄勪欢" top="5vh" width="800px">
+      <filePreview v-if="lookDialogVisible" :currentFile="{}"
+                   :fileUrl="javaApi+'/word/'+currentInfo.fileUrl" style="height: 90vh;overflow-y: auto;"/>
+    </el-dialog>
+    <FormDialog v-if="formDialog" ref="formDialog" @closeFormDia="closeFormDia"></FormDialog>
+  </div>
+</template>
+
+<script>
+import TableCard from '../caorui/TableCard/index.vue';
+import ZTTable from '../caorui/ZTTable/index.vue';
+import FormDialog from '../do/a8-customer-satisfaction/formDialog.vue';
+import filePreview from '../tool/file-preview.vue';
+
+export default {
+  name: 'a8-customer-satisfaction',
+  // import 寮曞叆鐨勭粍浠堕渶瑕佹敞鍏ュ埌瀵硅薄涓墠鑳戒娇鐢�
+  components: { filePreview, FormDialog, ZTTable, TableCard },
+  data() {
+    // 杩欓噷瀛樻斁鏁版嵁
+    return {
+      searchForm: {
+        unitName: '',
+      },
+      searchForm1: {
+        fileName: '',
+      },
+      tabIndex: '0',
+      tableColumn: [
+        {
+          label: '鍗曚綅鍚嶇О',
+          prop: 'unitName',
+          minWidth: '100'
+        },
+        {
+          label: '鏃ユ湡',
+          prop: 'fillDate',
+          minWidth: '100'
+        },
+        {
+          label: '濮撳悕',
+          prop: 'userName',
+          minWidth: '100'
+        },
+        {
+          label: '閮ㄩ棬',
+          prop: 'department',
+          minWidth: '100'
+        },
+        {
+          label: '鑱旂郴鐢佃瘽',
+          prop: 'contactNumber',
+          minWidth: '100'
+        },
+        {
+          label: '鍒涘缓鏃ユ湡',
+          prop: 'createTime',
+          minWidth: '100',
+        },
+        {
+          dataType: 'action',
+          minWidth: '80',
+          label: '鎿嶄綔',
+          operation: [
+            {
+              name: '缂栬緫',
+              type: 'text',
+              clickFun: (row) => {
+                this.openFormDia('edit', row);
+              },
+            },
+            {
+              name: '鍒犻櫎',
+              type: 'text',
+              color: '#f56c6c',
+              clickFun: (row) => {
+                this.delPlan(row)
+              }
+            }
+          ]
+        }
+      ],
+      tableData: [],
+      tableLoading: false,
+      page: {
+        size: 20,
+        current: 1,
+      },
+      total: 0,
+      tableColumn1: [
+        {
+          label: '闄勪欢鍚嶇О',
+          prop: 'fileName',
+          minWidth: '100'
+        },
+        {
+          label: '鍒涘缓浜�',
+          prop: 'userName',
+          minWidth: '100'
+        },
+        {
+          label: '鍒涘缓鏃堕棿',
+          prop: 'createTime',
+          minWidth: '100'
+        },
+        {
+          dataType: 'action',
+          minWidth: '50',
+          label: '鎿嶄綔',
+          operation: [
+            {
+              name: '棰勮',
+              type: 'text',
+              clickFun: (row) => {
+                this.handleLook(row)
+              }
+            },
+            {
+              name: '涓嬭浇',
+              type: 'text',
+              clickFun: (row) => {
+                this.upload(row);
+              },
+            },
+            {
+              name: '鍒犻櫎',
+              type: 'text',
+              color: '#f56c6c',
+              clickFun: (row) => {
+                this.delFile(row)
+              }
+            }
+          ]
+        }
+      ],
+      tableData1: [],
+      tableLoading1: false,
+      page1: {
+        size: 20,
+        current: 1,
+      },
+      total1: 0,
+      formDialog: false,
+      upLoading: false,
+      currentInfo:{},
+      lookDialogVisible: false,
+    };
+  },
+  mounted() {
+    this.searchList()
+  },
+  // 鏂规硶闆嗗悎
+  methods: {
+    // 鏌ヨ鍒楄〃
+    searchList () {
+      const entity = this.tabIndex === '0' ? this.searchForm : this.searchForm1
+      const page = this.tabIndex === '0' ? this.page : this.page1
+      if (this.tabIndex === '0') {
+        this.tableLoading = true
+        this.$axios.post(this.$api.clientSatisfaction.pageClientSatisfaction, {entity, page}, {
+          headers: {
+            "Content-Type": "application/json"
+          },
+          noQs: true
+        }).then(res => {
+          this.tableLoading = false
+          if (res.code === 201) return
+          this.tableData = res.data.records
+          this.total = res.data.total
+        }).catch(err => {
+          console.log('err---', err);
+          this.tableLoading = false
+        })
+      } else {
+        this.tableLoading1 = true
+        this.$axios.post(this.$api.clientSatisfaction.pageAnalyseFile, {entity, page}, {
+          headers: {
+            "Content-Type": "application/json"
+          },
+          noQs: true
+        }).then(res => {
+          this.tableLoading1 = false
+          if (res.code === 201) return
+          this.tableData1 = res.data.records
+          this.total1 = res.data.total
+        }).catch(err => {
+          console.log('err---', err);
+          this.tableLoading1 = false
+        })
+      }
+    },
+    openFormDia (type, row) {
+      this.formDialog = true
+      this.$nextTick(() => {
+        this.$refs.formDialog.openDia(type, row);
+      })
+    },
+    closeFormDia () {
+      this.formDialog = false
+      this.searchList()
+    },
+    // 閲嶇疆鏌ヨ鏉′欢
+    resetSearchForm () {
+      this.searchForm.unitName = '';
+      this.searchForm1.fileName = '';
+      this.searchList()
+    },
+    // 瀵煎叆娴佺▼
+    beforeUpload(file) {
+      if (file.size > 1024 * 1024 * 10) {
+        this.$message.error('涓婁紶鏂囦欢涓嶈秴杩�10M');
+        this.$refs.upload.clearFiles()
+        return false;
+      } else {
+        this.upLoading = true;
+        return true;
+      }
+    },
+    onError(err, file, fileList) {
+      this.$message.error('涓婁紶澶辫触')
+      this.$refs.upload.clearFiles()
+    },
+    handleSuccessUp(response) {
+      this.upLoading = false;
+      if (response.code == 200) {
+        this.$message.success('涓婁紶鎴愬姛');
+        this.searchList()
+      }
+    },
+    // 鍒犻櫎瀹㈡埛婊℃剰搴�
+    delPlan (row) {
+      this.$confirm('姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ暟鎹�, 鏄惁缁х画?', '鎻愮ず', {
+        confirmButtonText: '纭畾',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning'
+      }).then(() => {
+        this.tableLoading = true
+        this.$axios.get(this.$api.clientSatisfaction.delClientSatisfaction + '?clientSatisfactionId=' + row.clientSatisfactionId).then(res => {
+          this.tableLoading = false
+          if (res.code === 201) return
+          this.$message.success('鍒犻櫎鎴愬姛')
+          this.searchList()
+        }).catch(err => {
+          this.tableLoading = false
+          console.log('err---', err);
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '宸插彇娑堝垹闄�'
+        });
+      });
+    },
+    // 鏌ョ湅鏂囦欢
+    handleLook(row){
+      this.currentInfo = row
+      this.lookDialogVisible = true
+    },
+    // 涓嬭浇瀹㈡埛绂忓缓
+    upload (row) {
+      let url = '';
+      if(row.type==1){
+        url = this.javaApi+'/img/'+row.fileUrl
+        file.downloadIamge(url,row.fileName)
+      }else{
+        url = this.javaApi+'/word/'+row.fileUrl
+        const link = document.createElement('a');
+        link.href = url;
+        link.download = row.fileName;
+        link.click();
+      }
+    },
+    // 鍒犻櫎瀹㈡埛鍒嗘瀽闄勪欢
+    delFile (row) {
+      this.$confirm('姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ暟鎹�, 鏄惁缁х画?', '鎻愮ず', {
+        confirmButtonText: '纭畾',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning'
+      }).then(() => {
+        this.tableLoading = true
+        this.$axios.get(this.$api.clientSatisfaction.delAnalyseFile + '?analyseFileId=' + row.analyseFileId).then(res => {
+          this.tableLoading = false
+          if (res.code === 201) return
+          this.$message.success('鍒犻櫎鎴愬姛')
+          this.searchList()
+        }).catch(err => {
+          this.tableLoading = false
+          console.log('err---', err);
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '宸插彇娑堝垹闄�'
+        });
+      });
+    },
+    // 鍒嗛〉
+    handleSizeChange(val) {
+      this.page.size = val;
+      this.searchList();
+    },
+    handleCurrentChange(val) {
+      this.page.current = val;
+      this.searchList();
+    },
+    //
+    // 鍒嗛〉
+    handleSizeChange1(val) {
+      this.page1.size = val;
+      this.searchList();
+    },
+    handleCurrentChange1(val) {
+      this.page1.current = val;
+      this.searchList();
+    },
+    //
+  },
+  // 鐢ㄤ簬涓婁紶鏂囦欢鐨勪俊鎭�
+  computed: {
+    headers() {
+      return {
+        'token': sessionStorage.getItem('token')
+      }
+    },
+    action() {
+      return this.javaApi + this.$api.clientSatisfaction.uploadAnalyseFile
+    }
+  },
+};
+</script>
+
+<style scoped>
+.view-title {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  height: 60px;
+  padding-left: 20px;
+}
+
+.search-background {
+  width: 100%;
+  height: 80px;
+  line-height: 80px;
+  background-color: #ffffff;
+  display: flex;
+}
+
+.search-group {
+  display: flex;
+  align-items: center;
+  margin: 0 20px;
+}
+
+.table {
+  margin-top: 20px;
+  background-color: #ffffff;
+  padding-top: 20px;
+}
+.table-tab {
+  margin: 0 20px 20px 20px;
+}
+</style>

--
Gitblit v1.9.3