smmTargetbase.vue 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
  1. <template>
  2. <div class="smmTarget-container" id="box">
  3. <div class="left-cont minHeight" id="left">
  4. <div class="left-top">
  5. <el-button
  6. v-permission="permissionBtn.dataSourcePermission.smmData_export"
  7. style="width: 100%"
  8. type="primary"
  9. plain
  10. size="medium"
  11. @click="exportClick"
  12. :loading="btnload"
  13. >导出Excel</el-button
  14. >
  15. <el-autocomplete
  16. style="margin: 20px 0; width: 100%"
  17. prefix-icon="el-icon-search"
  18. v-model="leftSearchVal"
  19. :fetch-suggestions="handleLeftSearch"
  20. :trigger-on-focus="false"
  21. placeholder="指标名称/指标ID"
  22. @select="handleSelectLeftSearchval"
  23. popper-class="el-autocomplete-suggestion-data-entry"
  24. clearable
  25. >
  26. <template slot-scope="scope">
  27. <div v-if="scope.item.nodata" style="text-align: center">
  28. 暂无数据
  29. </div>
  30. <div v-else>
  31. {{ scope.item.IndexName }}
  32. </div>
  33. </template>
  34. </el-autocomplete>
  35. </div>
  36. <!-- <ul class="classify-list">
  37. <li
  38. :class="[
  39. 'classify-item',
  40. { act: select_classify === item.TypeCode },
  41. ]"
  42. v-for="item in classifyList"
  43. :key="item.TypeCode"
  44. @click="changeClassify(item.TypeCode)"
  45. >
  46. {{ item.TypeName }}
  47. </li>
  48. </ul> -->
  49. <div class="scroll-wrap">
  50. <el-tree
  51. ref="treeRef"
  52. class="target_tree custom-tree"
  53. :data="classifyList"
  54. node-key="UniqueCode"
  55. :props="{
  56. label: 'ClassifyName',
  57. children: 'Children',
  58. }"
  59. draggable
  60. :current-node-key="select_node"
  61. :expand-on-click-node="false"
  62. check-strictly
  63. empty-text="暂无分类"
  64. @current-change="nodeChangeHandle"
  65. :default-expanded-keys="defaultShowNodes"
  66. @node-expand="handleNodeExpand"
  67. @node-collapse="handleNodeCollapse"
  68. :allow-drag="canDragHandle"
  69. :allow-drop="canDropHandle"
  70. @node-drop="dropOverHandle"
  71. >
  72. <div class="custom-tree-node" slot-scope="{ node, data }">
  73. <span
  74. class="text_oneLine"
  75. :style="`width:${
  76. (select_node === data.UniqueCode &&
  77. (node.Nodewidth || data.NodeWidth + 'px')) ||
  78. ''
  79. }`"
  80. >{{ data.ClassifyName }}</span
  81. >
  82. <div v-if="select_node === data.UniqueCode">
  83. <img
  84. src="~@/assets/img/data_m/move_ico.png"
  85. v-if="data.Button.MoveButton"
  86. alt=""
  87. style="width: 14px; height: 14px; margin-right: 5px"
  88. @click.stop="clickClassifyHandle('move', data, node)"
  89. />
  90. <img
  91. src="~@/assets/img/set_m/add.png"
  92. style="width: 14px; height: 14px; margin-right: 5px"
  93. @click.stop="clickClassifyHandle('add', data, node)"
  94. v-if="data.Button.AddButton"
  95. />
  96. <img
  97. src="~@/assets/img/set_m/edit.png"
  98. v-if="data.Button.OpButton"
  99. alt=""
  100. style="width: 14px; height: 14px; margin-right: 5px"
  101. @click.stop="clickClassifyHandle('edit', data, node)"
  102. />
  103. <img
  104. src="~@/assets/img/set_m/clean.png"
  105. v-if="data.Button.cleanButton"
  106. alt=""
  107. style="width: 14px; height: 14px; margin-right: 5px"
  108. @click.stop="clickClassifyHandle('clean', data, node)"
  109. />
  110. <img
  111. src="~@/assets/img/set_m/del.png"
  112. v-if="data.Button.DeleteButton"
  113. alt=""
  114. style="width: 14px; height: 14px"
  115. @click.stop="clickClassifyHandle('del', data, node)"
  116. />
  117. <img
  118. src="~@/assets/img/set_m/del_icon.png"
  119. v-if="data.Button.targetDelButton"
  120. alt=""
  121. style="width: 14px; height: 14px; margin-right: 5px"
  122. @click.stop="clickClassifyHandle('delTarget', data, node)"
  123. />
  124. </div>
  125. </div>
  126. </el-tree>
  127. <div class="add-cont" @click="addClassifyHandle">
  128. <img
  129. src="~@/assets/img/set_m/add_ico.png"
  130. alt=""
  131. style="width: 16px; height: 16px; margin: 10px"
  132. />
  133. <span>添加分类</span>
  134. </div>
  135. </div>
  136. <span
  137. class="move-btn resize"
  138. v-drag
  139. id="resize"
  140. @mousemove="dynamicNode && resetNodeStyle(dynamicNode)"
  141. >
  142. </span>
  143. </div>
  144. <div
  145. class="right-cont minHeight"
  146. id="right"
  147. v-loading="dataloading"
  148. element-loading-text="获取数据中..."
  149. >
  150. <template v-if="rightShow">
  151. <div class="right-box" @scroll="scrollHandle">
  152. <div class="data-header">
  153. <lz-table
  154. :tableOption="tableOption"
  155. tableType="header"
  156. ref="table"
  157. source="smm"
  158. />
  159. </div>
  160. <div class="data-cont" v-if="dateArr.length">
  161. <lz-table
  162. :tableOption="tableOption"
  163. tableType="data"
  164. :dateArr="dateArr"
  165. source="smm"
  166. />
  167. </div>
  168. <div v-else class="nodata"></div>
  169. </div>
  170. <div class="frequency-list" v-if="rightShow && !isShowSingleData">
  171. <el-button
  172. type="primary"
  173. class="frequency-btn"
  174. :plain="select_frequency !== item.key"
  175. v-for="item in frequencyList"
  176. :key="item.key"
  177. @click="changeFrequency(item.key)"
  178. >{{ item.key }}</el-button
  179. >
  180. </div>
  181. </template>
  182. <div v-else class="nodata-cont">
  183. <tableNoData text="暂无数据"/>
  184. </div>
  185. </div>
  186. <!-- 添加/编辑分类弹窗 -->
  187. <m-dialog
  188. :show.sync="openClassifyDia"
  189. width="700px"
  190. :title="classifyForm.title"
  191. @close="cancelDialogHandle"
  192. >
  193. <div class="dialog-cont smmTarget-dialog-cont">
  194. <el-form
  195. ref="classifyFormRef"
  196. label-position="left"
  197. hide-required-asterisk
  198. label-width="80px"
  199. :model="classifyForm"
  200. :rules="classifyFormRules"
  201. >
  202. <el-form-item
  203. label="一级目录"
  204. v-if="classifyForm.parent_classify_name"
  205. >
  206. <span>{{ classifyForm.parent_classify_name }}</span>
  207. </el-form-item>
  208. <el-form-item
  209. label="分类名称"
  210. prop="classify_name"
  211. v-if="classifyForm.type === 'classify'"
  212. >
  213. <el-input
  214. v-model="classifyForm.classify_name"
  215. style="width: 80%"
  216. placeholder="请输入分类名称"
  217. />
  218. </el-form-item>
  219. <el-form-item label="分类名称" prop="classifys_id" v-else>
  220. <el-cascader
  221. style="width: 80%"
  222. :key="cascaderKey"
  223. placeholder="请选择分类名称"
  224. v-model="classifyForm.classifys_id"
  225. :options="cascaderList"
  226. :props="{
  227. value: 'ClassifyId',
  228. label: 'ClassifyName',
  229. children: 'Children',
  230. }"
  231. />
  232. </el-form-item>
  233. </el-form>
  234. </div>
  235. <div class="dia-bot">
  236. <el-button
  237. type="primary"
  238. style="margin-right: 20px"
  239. @click="saveClassifyHandle"
  240. >保存</el-button
  241. >
  242. <el-button type="primary" plain @click="cancelDialogHandle"
  243. >取消</el-button
  244. >
  245. </div>
  246. </m-dialog>
  247. </div>
  248. </template>
  249. <script>
  250. import lzTable from "@/components/lzTable.vue";
  251. import { smmDataInterface } from "@/api/api.js";
  252. import mDialog from "@/components/mDialog.vue";
  253. import leftMixin from "./mixins/leftMixin.js";
  254. export default {
  255. name: "",
  256. components: { lzTable, mDialog },
  257. mixins: [leftMixin],
  258. watch: {},
  259. data() {
  260. return {
  261. exportBase: process.env.VUE_APP_API_ROOT + "/datamanage/export/smmList", //ssm数据导出接口
  262. dataloading: false,
  263. rightShow: false,
  264. select_classify: "",
  265. classifyList: [],
  266. select_frequency: "",
  267. frequencyList: [],
  268. tableOption: [],
  269. dateArr: [], //最长的日期数组
  270. btnload: false,
  271. page_no: 1,
  272. page_size: 20,
  273. havemore: true, //是否还有数据
  274. leftSearchVal: "", //左侧搜索值
  275. leftSearchTradeCode: "", //如果是搜索选择的 则有此code
  276. select_quota: "", // 选择的指标名
  277. select_Unit: "", // 选择的单位
  278. select_ModifyTime: "", //选中的更新时间
  279. select_breed: "", // 选中的分类名称
  280. isShowSingleData: false, //右侧是否展示的是单个指标数据
  281. singleDataCode: "",
  282. cascaderList: [], //移动指标分类列表
  283. cascaderKey: 0,
  284. openClassifyDia: false, //分类弹窗
  285. classifyForm: {
  286. title: "添加分类",
  287. classify_name: "", //分类名称
  288. classify_id: "", //分类id
  289. parent_classify_name: "", //如果是二级分类,这是所属一级分类的名称
  290. parent_classify_id: "", //如果是二级分类,这是所属一级分类的id
  291. type: "classify", //classify|index 对分类还是指标进行操作
  292. classifys_id: [], //如果是指标,这是选中的分类id[一级分类id,二级分类id]
  293. BaseFromSmmIndexId: "", //如果是指标,这是指标的唯一id
  294. }, //弹窗可编辑信息
  295. classifyFormRules: {
  296. classify_name: [
  297. { required: true, message: "分类名称不能为空", trigger: "blur" },
  298. ],
  299. }, //可编辑信息校验
  300. };
  301. },
  302. methods: {
  303. /* 获取分类 */
  304. getClassify() {
  305. smmDataInterface.classifyList().then((res) => {
  306. if (res.Ret !== 200) return;
  307. let Data = res.Data.List || [];
  308. //对分类数据做处理:
  309. this.classifyList = this.formatClassifyData(Data, 1, 0);
  310. });
  311. },
  312. formatClassifyData(arr, level, topParentNodeId) {
  313. arr.forEach((item) => {
  314. const { ClassifyId, BaseFromSmmIndexId, BaseFromSmmIndexCode } = item;
  315. //每条数据添加UniqueCode属性,由ClassifyId BaseFromSmmIndexId BaseFromSmmIndexCode拼接
  316. item.UniqueCode = `${ClassifyId}_${BaseFromSmmIndexId}_${BaseFromSmmIndexCode}`;
  317. //添加Button属性,用于控制操作栏
  318. item.Button = {
  319. AddButton: true,
  320. OpButton: true,
  321. DeleteButton: true,
  322. MoveButton: true,
  323. cleanButton: false,
  324. targetDelButton: false,
  325. };
  326. //未分类禁用所有操作栏
  327. if (item.ClassifyId === 0) {
  328. item.Button = {
  329. AddButton: false,
  330. OpButton: false,
  331. DeleteButton: false,
  332. MoveButton: false,
  333. cleanButton: false,
  334. targetDelButton: false,
  335. };
  336. }
  337. //二级分类禁用添加按钮
  338. if (item.Level === 2) {
  339. item.Button = {
  340. AddButton: false,
  341. OpButton: true,
  342. DeleteButton: true,
  343. MoveButton: true,
  344. cleanButton: false,
  345. targetDelButton: false,
  346. };
  347. }
  348. //指标禁用删除按钮
  349. if (item.BaseFromSmmIndexCode) {
  350. item.Button = {
  351. AddButton: false,
  352. OpButton: true,
  353. DeleteButton: false,
  354. MoveButton: true,
  355. cleanButton: true,
  356. targetDelButton: true,
  357. };
  358. //未分类下的指标,禁用清除按钮
  359. if (topParentNodeId === 0) {
  360. item.Button["cleanButton"] = false;
  361. }
  362. }
  363. //非一级分类添加一级父节点id
  364. if (level !== 1) {
  365. item.topParentNodeId = topParentNodeId;
  366. }
  367. if (item.Children && item.Children.length) {
  368. this.formatClassifyData(
  369. item.Children,
  370. level + 1,
  371. level === 1 ? item.ClassifyId : item.ParentId
  372. );
  373. }
  374. });
  375. return arr;
  376. },
  377. /* 获取频度 */
  378. async getFrequency(defaultSelect) {
  379. const res = await smmDataInterface.frequencyList({
  380. ClassifyId: this.select_classify,
  381. });
  382. if (res.Ret !== 200) return;
  383. this.frequencyList = res.Data
  384. ? res.Data.map((item) => {
  385. return {
  386. key: item.Frequency,
  387. };
  388. })
  389. : [];
  390. //设置当前选中的频度,若传入有默认选项则选中默认频度,否则选中列表第一个
  391. this.select_frequency =
  392. defaultSelect ||
  393. (this.frequencyList.length ? this.frequencyList[0].key : "");
  394. !this.frequencyList.length && this.nodataDeal();
  395. },
  396. /* 获取数据 */
  397. getDataList: _.throttle(function () {
  398. this.isShowSingleData = false;
  399. this.dataloading = true;
  400. smmDataInterface
  401. .dataList({
  402. ClassifyId: this.select_classify,
  403. Frequency: this.select_frequency,
  404. PageSize: this.page_size,
  405. CurrentIndex: this.page_no,
  406. })
  407. .then((res) => {
  408. this.rightShow = true;
  409. if (res.Ret !== 200) return;
  410. // 找出最多的页码 判断是否还有数据
  411. let page_arrs = res.Data.map((item) => item.Paging.Pages);
  412. let totalPage = Math.max.apply(Math, page_arrs);
  413. this.havemore = this.page_no < totalPage ? true : false;
  414. // 合并数据
  415. if (this.page_no === 1) {
  416. this.tableOption = res.Data;
  417. } else {
  418. this.tableOption.forEach((item) => {
  419. res.Data.forEach((_item) => {
  420. if (item.IndexCode === _item.IndexCode) {
  421. item.DataList = item.DataList.concat(_item.DataList);
  422. }
  423. });
  424. });
  425. }
  426. // 合并所有指标中的日期 作为日期数组
  427. let arr = res.Data.map((item) => {
  428. return item.DataList;
  429. });
  430. let obj = [];
  431. for (let i of arr) {
  432. for (let j of i) {
  433. obj.push(j.DataTime);
  434. }
  435. }
  436. let arr2 = [...new Set(obj)].sort().reverse();
  437. let concatArr = [...new Set([...this.dateArr, ...arr2])]
  438. .sort()
  439. .reverse();
  440. this.dateArr = this.page_no === 1 ? arr2 : concatArr;
  441. /* 不满6个追加6个空的显示一排 别问 问就是为了美观 */
  442. if (this.tableOption.length < 7)
  443. for (let i = 0; i < 7; i++) {
  444. this.tableOption.push({
  445. DataList: [],
  446. });
  447. if (this.tableOption.length >= 7) break;
  448. }
  449. //数据最大长度小于12个 追加数据满12个 别问 问就是为了美观
  450. if (this.dateArr.length < 12)
  451. for (let i = 0; i < 12; i++) {
  452. this.dateArr.push("");
  453. if (this.dateArr.length >= 12) break;
  454. }
  455. this.dataloading = false;
  456. this.page_no === 1 &&
  457. this.$nextTick(() => {
  458. this.rightShow && this.initWidth();
  459. });
  460. });
  461. }, 200),
  462. // 获取单个指标数据
  463. async getTargetDataList(code) {
  464. this.isShowSingleData = true;
  465. this.dataloading = true;
  466. try {
  467. const res = await smmDataInterface.getTargetDataList({
  468. IndexCode: code,
  469. });
  470. this.rightShow = true;
  471. if (res.Ret !== 200) return;
  472. const DataList = res.Data.Data || [];
  473. // 设置为没有更多数据
  474. this.haveMore = false;
  475. // 合并数据
  476. this.tableOption = [
  477. {
  478. DataList: DataList,
  479. ...res.Data,
  480. },
  481. ];
  482. // 这里是单个指标所以不用合并日期
  483. const arr = DataList.map((item) => item.DataTime);
  484. this.dateArr = [...new Set(arr)].sort().reverse();
  485. /* 不满6个追加6个空的显示一排 别问 问就是为了美观 */
  486. for (let i = 0; i < 7; i++) {
  487. this.tableOption.push({
  488. DataList: [],
  489. });
  490. if (this.tableOption.length >= 7) break;
  491. }
  492. //数据最大长度小于12个 追加数据满12个 别问 问就是为了美观
  493. if (this.dateArr.length < 12)
  494. for (let i = 0; i < 12; i++) {
  495. this.dateArr.push("");
  496. if (this.dateArr.length >= 12) break;
  497. }
  498. this.select_quota = res.Data.IndexName;
  499. this.select_Unit = res.Data.Unit;
  500. this.select_ModifyTime = res.Data.ModifyTime || "";
  501. this.dataloading = false;
  502. this.rightShow && this.initWidth();
  503. } catch (err) {
  504. console.log(err);
  505. }
  506. },
  507. /* 改变品种 */
  508. changeClassify(id) {
  509. this.select_classify = id;
  510. this.select_breed = id;
  511. this.leftSearchVal = "";
  512. this.leftSearchTradeCode = "";
  513. this.select_Unit = "";
  514. this.select_ModifyTime = "";
  515. },
  516. /* 改变频度 */
  517. changeFrequency(key) {
  518. this.select_frequency = key;
  519. this.leftSearchVal = "";
  520. this.getDataList();
  521. },
  522. initWidth() {
  523. this.$nextTick(() => {
  524. $(".right-box")[0].style.width =
  525. this.$refs.table.$el.clientWidth + 5 + "px";
  526. $(".right-box")[0].scrollTop = 0;
  527. $(".right-box")[0].scrollLeft = 0;
  528. });
  529. },
  530. /* 无频度的异常显示处理 7*12*/
  531. nodataDeal() {
  532. this.tableOption = [];
  533. this.dateArr = [];
  534. for (let i = 0; i < 7; i++) {
  535. this.tableOption.push({
  536. DataList: [],
  537. });
  538. if (this.tableOption.length >= 7) break;
  539. }
  540. for (let i = 0; i < 12; i++) {
  541. this.dateArr.push("");
  542. if (this.dateArr.length >= 12) break;
  543. }
  544. },
  545. /* 滚动加载 */
  546. scrollHandle(e) {
  547. if (this.isShowSingleData) return;
  548. const dom = e.target;
  549. let total = dom.scrollTop + dom.clientHeight;
  550. if (total >= dom.scrollHeight && this.havemore) {
  551. this.page_no++;
  552. console.log("load下一页");
  553. this.getDataList();
  554. }
  555. },
  556. /* 数据导出 */
  557. exportClick() {
  558. this.btnload = true;
  559. const link = document.createElement("a");
  560. link.href = this.exportSmmapi;
  561. link.download = "";
  562. link.click();
  563. console.log({
  564. IndexName: this.select_quota,
  565. IndexCode: this.leftSearchTradeCode,
  566. sendIndexCode: this.escapeStr(this.leftSearchTradeCode),
  567. TypeName: this.select_breed,
  568. sendTypeName: this.escapeStr(this.select_breed),
  569. Frequency: this.select_frequency,
  570. UnitName: this.select_Unit,
  571. ModifyTime: this.select_ModifyTime,
  572. sendToken: this.escapeStr(localStorage.getItem("auth") || ""),
  573. url: this.exportSmmapi,
  574. });
  575. setTimeout(() => {
  576. this.btnload = false;
  577. }, 5000);
  578. },
  579. //左侧搜索
  580. async handleLeftSearch(query, cb) {
  581. cb([]);
  582. if (!query) return;
  583. const res = await smmDataInterface.getTargetListByName({
  584. Keyword: query,
  585. });
  586. if (res.Ret === 200) {
  587. let arr = res.Data || [];
  588. if (!arr.length) {
  589. cb([{ nodata: true }]);
  590. } else {
  591. cb(arr);
  592. }
  593. }
  594. },
  595. // 选中左侧搜索值
  596. handleSelectLeftSearchval(e) {
  597. if (!e.IndexCode) return;
  598. //this.select_frequency=e.Frequency
  599. //this.select_classify=e.Type2+'#'+e.Type3
  600. this.leftSearchTradeCode = e.IndexCode;
  601. this.leftSearchVal = e.IndexName;
  602. this.select_quota = e.IndexName;
  603. this.select_Unit = e.Unit;
  604. this.select_ModifyTime = e.ModifyTime;
  605. this.select_breed = "";
  606. // 关闭watcher
  607. this.isAuto = false;
  608. // 获取单独指标数据
  609. this.getTargetDataList(e.IndexCode);
  610. this.$nextTick(() => {
  611. //找到父节点并展开
  612. const targetData = this.getTargetData(e.IndexCode, this.classifyList);
  613. if (targetData) {
  614. //一级节点
  615. const { topParentNodeId, UniqueCode } = targetData;
  616. this.handleNodeExpand({ UniqueCode: `${topParentNodeId}_0_` });
  617. //二级节点
  618. if (topParentNodeId !== 0) {
  619. const secondNodeId = UniqueCode.split("_")[0];
  620. this.handleNodeExpand({ UniqueCode: `${secondNodeId}_0_` });
  621. }
  622. //节点样式变化
  623. const tree = $(".target_tree")[0];
  624. let width = tree.offsetWidth;
  625. let label_width =
  626. width > 500 ? "auto" : width <= 500 ? 90 : 0.7 * width;
  627. targetData.NodeWidth = label_width;
  628. this.select_node = UniqueCode;
  629. this.$refs.treeRef.setCurrentNode(targetData);
  630. const node = this.$refs.treeRef.getCurrentNode();
  631. this.resetNodeStyle(node);
  632. }
  633. //this.handleScrollLeftWrap()
  634. });
  635. },
  636. // 左侧滚动
  637. handleScrollLeftWrap() {
  638. let top = $(".act")[0].offsetTop;
  639. $(".classify-list").animate({
  640. scrollTop: top - 200,
  641. });
  642. },
  643. getTargetData(code, arr) {
  644. for (const item of arr) {
  645. if (item.BaseFromSmmIndexCode === code) return item;
  646. if (item.Children && item.Children.length) {
  647. const _item = this.getTargetData(code, item.Children);
  648. if (_item) return _item;
  649. }
  650. }
  651. },
  652. // 对[#,;]转义
  653. escapeStr(str) {
  654. return str.replace(/#/g, escape("#")).replace(/;/g, escape(";"));
  655. },
  656. //节点操作:
  657. clickClassifyHandle(type, data, node) {
  658. const optionMap = {
  659. /* 'move':this.moveNode,移动 */
  660. add: this.addClassifyHandle, //添加分类
  661. edit: this.editClassifyHandle, //编辑分类/移动指标
  662. del: this.deleteClassifyHandle, //删除分类
  663. clean: this.cleanClassifyHandle, //清除指标分类
  664. delTarget: this.deleteTarget, //删除指标
  665. };
  666. optionMap[type] && optionMap[type](data, node);
  667. },
  668. //添加一二级分类
  669. addClassifyHandle(data = null, node = null) {
  670. this.classifyForm = {
  671. ...this.classifyForm,
  672. ...(data
  673. ? {
  674. title: "添加分类",
  675. classify_name: "",
  676. parent_classify_name: data.ClassifyName,
  677. parent_classify_id: data.ClassifyId,
  678. }
  679. : {
  680. title: "添加分类",
  681. classify_name: "",
  682. }),
  683. };
  684. this.openDialogHandle();
  685. },
  686. //编辑一二级分类,编辑指标
  687. async editClassifyHandle(data, node) {
  688. //console.log('data',data,'node',node)
  689. const { level, parent } = node;
  690. const parentNodeId = parent.data.ClassifyId;
  691. const { ClassifyName, topParentNodeId, ClassifyId, BaseFromSmmIndexId } =
  692. data;
  693. let tempForm = {
  694. parent_classify_name: "",
  695. parent_classify_id: "",
  696. };
  697. let type = "classify";
  698. let classifys_id = [];
  699. //是二级分类(二级,且父节点不是未分类节点)
  700. if (level === 2 && parentNodeId !== 0) {
  701. const { parent } = node;
  702. tempForm.parent_classify_id = data.ParentId;
  703. tempForm.parent_classify_name = parent.data.ClassifyName;
  704. }
  705. //是指标(三级,或二级,父节点为未分类节点)
  706. if (level === 3 || (level === 2 && parentNodeId === 0)) {
  707. type = "index";
  708. this.cascaderKey++; //更新el-cascader
  709. //获取cascaderList数据
  710. const res = await smmDataInterface.classifyNameList();
  711. if (res.Ret !== 200) return;
  712. this.cascaderList = res.Data.List;
  713. //如果指标不在未分类节点下,需回显值
  714. if (parentNodeId) {
  715. classifys_id = [topParentNodeId, parentNodeId];
  716. }
  717. }
  718. this.classifyForm = {
  719. ...{
  720. title: type === "index" ? "编辑指标" : "编辑分类",
  721. classify_name: ClassifyName,
  722. classify_id: ClassifyId,
  723. type,
  724. classifys_id,
  725. BaseFromSmmIndexId: BaseFromSmmIndexId || "",
  726. },
  727. ...tempForm,
  728. };
  729. this.openDialogHandle();
  730. },
  731. //删除一二级分类
  732. deleteClassifyHandle(data, node) {
  733. const { Children, ClassifyId } = data;
  734. //如果分类下有子分类或指标
  735. let hintText =
  736. Children && Children.length
  737. ? "删除分类将同步删除分类下所有子分类,确认删除吗?"
  738. : "删除分类不可恢复,确定删除吗?";
  739. this.$confirm(hintText, "提示", {
  740. confirmButtonText: "确定",
  741. cancelButtonText: "取消",
  742. type: "warning",
  743. })
  744. .then(() => {
  745. //删除接口
  746. smmDataInterface
  747. .deleteClassifyItem({
  748. ClassifyId,
  749. })
  750. .then((res) => {
  751. if (res.Ret !== 200) return;
  752. this.$message.success("删除成功");
  753. this.getClassify();
  754. });
  755. })
  756. .catch(() => {});
  757. },
  758. //清除指标分类
  759. cleanClassifyHandle(data, node) {
  760. const { BaseFromSmmIndexId } = data;
  761. smmDataInterface
  762. .cleanClassify({
  763. BaseFromSmmIndexId,
  764. })
  765. .then((res) => {
  766. if (res.Ret !== 200) return;
  767. this.$message.success("清除分类成功");
  768. this.getClassify();
  769. });
  770. },
  771. //删除指标
  772. deleteTarget(data, node) {
  773. const { BaseFromSmmIndexId } = data;
  774. this.$confirm("指标删除后不可被引用,确认删除吗?", "提示", {
  775. confirmButtonText: "确定",
  776. cancelButtonText: "取消",
  777. type: "warning",
  778. })
  779. .then(() => {
  780. smmDataInterface
  781. .deleteSMMtarget({
  782. BaseFromSmmIndexId,
  783. })
  784. .then((res) => {
  785. if (res.Ret !== 200) return;
  786. this.$message.success("删除成功");
  787. this.getClassify();
  788. });
  789. //删除指标接口
  790. })
  791. .catch(() => {});
  792. },
  793. //打开分类弹窗
  794. openDialogHandle() {
  795. //this.$refs.classifyFormRef.clearValidate();
  796. this.openClassifyDia = true;
  797. },
  798. //关闭分类弹窗
  799. cancelDialogHandle() {
  800. this.$refs.classifyFormRef.clearValidate();
  801. this.openClassifyDia = false;
  802. this.classifyForm.classify_name = "";
  803. this.classifyForm.type = "classify";
  804. },
  805. //保存更改
  806. async saveClassifyHandle() {
  807. const {
  808. type,
  809. title,
  810. classify_name,
  811. classifys_id,
  812. parent_classify_id,
  813. classify_id,
  814. BaseFromSmmIndexId,
  815. } = this.classifyForm;
  816. let res = null;
  817. let optionType = title.includes("添加") ? "添加" : "编辑";
  818. //对分类进行操作
  819. if (type === "classify") {
  820. //检查classify_name
  821. if (!classify_name.length) {
  822. this.$message.warning("请输入分类名称");
  823. return;
  824. }
  825. //添加分类
  826. if (title.includes("添加")) {
  827. res = await smmDataInterface.addClassifyItem({
  828. ParentId: parent_classify_id || 0,
  829. ClassifyName: classify_name,
  830. });
  831. //编辑分类
  832. } else {
  833. res = await smmDataInterface.editClassifyItem({
  834. ClassifyId: classify_id,
  835. ClassifyName: classify_name,
  836. });
  837. }
  838. }
  839. //对指标进行操作
  840. if (type === "index") {
  841. //检查classifys_id
  842. if (!classifys_id.length) {
  843. this.$message.warning("请选择分类");
  844. return;
  845. }
  846. //编辑指标(移动指标)
  847. res = await smmDataInterface.editSmmTarget({
  848. ClassifyId: classifys_id[1],
  849. BaseFromSmmIndexId: BaseFromSmmIndexId,
  850. });
  851. }
  852. if (res.Ret !== 200) return;
  853. this.$message.success(`${optionType}成功`);
  854. this.getClassify();
  855. this.cancelDialogHandle();
  856. },
  857. //改变选中节点
  858. nodeChangeHandle(data, node) {
  859. if (data.UniqueCode === this.select_node) return;
  860. const { level, parent } = node;
  861. const parentNodeId = parent.data.ClassifyId;
  862. const Children = data.Children || [];
  863. this.dynamicNode = node;
  864. this.select_node = data.UniqueCode;
  865. this.page_no = 1;
  866. this.page_size = 20;
  867. this.resetNodeStyle(node);
  868. //如果是二级分类 或是一级分类的未分类
  869. if (
  870. (level === 2 && parentNodeId !== 0 && Children.length) ||
  871. (level === 1 && data.ClassifyId === 0 && Children.length)
  872. ) {
  873. this.getClassifyData(data.ClassifyId);
  874. //如果是指标
  875. } else if (level === 3 || (level === 2 && parentNodeId === 0)) {
  876. this.getSmmData(data.BaseFromSmmIndexCode);
  877. //如果是一级分类或空的二级指标
  878. } else if (level === 1 || (level === 2 && !Children.length)) {
  879. this.rightShow = false;
  880. this.isShowSingleData = false;
  881. }
  882. },
  883. //获取二级分类的表格数据
  884. async getClassifyData(id) {
  885. this.select_classify = id;
  886. this.select_frequency = "";
  887. await this.getFrequency();
  888. this.getDataList();
  889. },
  890. //获取指标数据
  891. getSmmData(code) {
  892. this.singleDataCode = code;
  893. this.getTargetDataList(code);
  894. },
  895. //判断节点是否能放入
  896. canDropHandle(draggingNode, dropNode, type) {
  897. //console.log('drag',draggingNode)
  898. //console.log('drop',dropNode)
  899. const { level } = draggingNode;
  900. const dragParentId = draggingNode.data.ParentId;
  901. const dropClassifyId = dropNode.data.ClassifyId;
  902. const dropParentId = dropNode.data.ParentId;
  903. let canDrop = false;
  904. //level===1 一级节点 可以在一级节点之间移动 当dropNode不为未分类时,可以移动
  905. if (
  906. level === 1 &&
  907. dropNode.level === 1 &&
  908. type !== "inner" &&
  909. dropClassifyId !== 0
  910. ) {
  911. canDrop = true;
  912. }
  913. //level===2 二级节点 或 未分类下的指标
  914. if (level === 2) {
  915. //是未分类下的指标
  916. if (dragParentId === 0) {
  917. //在当前目录(未分类)内移动
  918. //移动到其他分类下的二级目录内
  919. if (
  920. (dropNode.level === 2 && dropParentId === 0 && type !== "inner") ||
  921. (dropNode.level === 2 && dropParentId !== 0 && type === "inner") ||
  922. (dropNode.level === 3 && type !== "inner") ||
  923. (dropNode.level === 1 && type === "inner" && dropClassifyId === 0)
  924. ) {
  925. canDrop = true;
  926. }
  927. } else {
  928. //是二级节点
  929. //在目录内移动
  930. //跨目录移动
  931. if (
  932. (dropNode.level === 2 && type !== "inner" && dropParentId !== 0) ||
  933. (dropNode.level === 1 && type === "inner" && dropClassifyId !== 0)
  934. ) {
  935. canDrop = true;
  936. }
  937. }
  938. }
  939. //level===3 指标
  940. if (level === 3) {
  941. if (
  942. (dropNode.level === 2 && type === "inner" && dropParentId !== 0) ||
  943. (dropNode.level === 3 && type !== "inner")
  944. ) {
  945. canDrop = true;
  946. }
  947. }
  948. return canDrop;
  949. },
  950. //拖拽移动节点处理
  951. dropOverHandle(draggingNode, dropNode, type, event) {
  952. const { level, data } = draggingNode;
  953. const parentNodeId = data.ParentId;
  954. //是指标
  955. if (level === 3 || (level === 2 && parentNodeId === 0)) {
  956. this.moveSMMTarge(draggingNode, dropNode, type, event);
  957. }
  958. //是目录
  959. if (level === 1 || (level == 2 && parentNodeId !== 0)) {
  960. this.moveCatalog(draggingNode, dropNode, type, event);
  961. }
  962. },
  963. //移动目录
  964. moveCatalog(drag, drop, type, event) {
  965. let PrevClassifyId = 0,
  966. NextClassifyId = 0,
  967. ClassifyId = 0,
  968. ParentId = 0;
  969. const list = drop.parent.childNodes;
  970. ParentId = drop.parent.data.ClassifyId || 0;
  971. ClassifyId = drag.data.ClassifyId;
  972. //目录间移动
  973. if (drag.level === drop.level) {
  974. //console.log(drop.data.ClassifyName)
  975. //找到最后进入的节点处于父节点的哪个位置
  976. const index = list.findIndex((item) => {
  977. return item.data.ClassifyId === drag.data.ClassifyId;
  978. });
  979. //如果在第一个
  980. if (index === 0) {
  981. PrevClassifyId = 0;
  982. NextClassifyId = list[index + 1].data.ClassifyId;
  983. } else if (index === list.length - 1) {
  984. //如果在最后一个
  985. PrevClassifyId = list[index - 1].data.ClassifyId;
  986. NextClassifyId = 0;
  987. } else {
  988. PrevClassifyId = list[index - 1].data.ClassifyId;
  989. NextClassifyId = list[index + 1].data.ClassifyId;
  990. }
  991. //跨目录移动,默认在第一个
  992. } else if (drag.level === 2 && type === "inner") {
  993. ParentId = drop.data.ClassifyId;
  994. PrevClassifyId = 0;
  995. NextClassifyId =
  996. drop.data.Children.length > 1 ? drop.data.Children[0].ClassifyId : 0;
  997. }
  998. //console.log('移动目录')
  999. /* console.log('ClassifyId',ClassifyId,'ParentId',ParentId)
  1000. console.log('PrevClassifyId',PrevClassifyId,'NextClassifyId',NextClassifyId) */
  1001. smmDataInterface
  1002. .moveCatalog({
  1003. ClassifyId,
  1004. ParentId,
  1005. PrevClassifyId,
  1006. NextClassifyId,
  1007. })
  1008. .then((res) => {
  1009. if (res.Ret !== 200) return;
  1010. this.$message.success("移动成功!");
  1011. this.getClassify();
  1012. });
  1013. },
  1014. //移动指标
  1015. moveSMMTarge(drag, drop, type, event) {
  1016. let PrevBaseFromSmmIndexId = 0,
  1017. NextBaseFromSmmIndexId = 0,
  1018. ClassifyId = 0,
  1019. BaseFromSmmIndexId = 0;
  1020. BaseFromSmmIndexId = drag.data.BaseFromSmmIndexId;
  1021. const list = drop.parent.childNodes;
  1022. ClassifyId = drop.data.ClassifyId;
  1023. if (type === "inner") {
  1024. PrevBaseFromSmmIndexId = 0;
  1025. NextBaseFromSmmIndexId =
  1026. drop.data.Children > 1 ? drop.data.Children[0].BaseFromSmmIndexId : 0;
  1027. } else {
  1028. const index = list.findIndex((item) => {
  1029. return item.data.BaseFromSmmIndexId === drag.data.BaseFromSmmIndexId;
  1030. });
  1031. if (index === 0) {
  1032. PrevBaseFromSmmIndexId = 0;
  1033. NextBaseFromSmmIndexId = list[index + 1].data.BaseFromSmmIndexId;
  1034. } else if (index === list.length - 1) {
  1035. PrevBaseFromSmmIndexId = list[index - 1].data.BaseFromSmmIndexId;
  1036. NextBaseFromSmmIndexId = 0;
  1037. } else {
  1038. PrevBaseFromSmmIndexId = list[index - 1].data.BaseFromSmmIndexId;
  1039. NextBaseFromSmmIndexId = list[index + 1].data.BaseFromSmmIndexId;
  1040. }
  1041. }
  1042. /* console.log('ClassifyId',ClassifyId,'BaseFromSmmIndexId',BaseFromSmmIndexId)
  1043. console.log('PrevBaseFromSmmIndexId',PrevBaseFromSmmIndexId,'NextBaseFromSmmIndexId',NextBaseFromSmmIndexId)
  1044. console.log('移动指标') */
  1045. smmDataInterface
  1046. .moveSMMtarget({
  1047. ClassifyId,
  1048. BaseFromSmmIndexId,
  1049. PrevBaseFromSmmIndexId,
  1050. NextBaseFromSmmIndexId,
  1051. })
  1052. .then((res) => {
  1053. if (res.Ret !== 200) return;
  1054. this.$message.success("移动成功!");
  1055. this.getClassify();
  1056. });
  1057. },
  1058. },
  1059. computed: {
  1060. exportSmmapi() {
  1061. // smm数据导出接口
  1062. let urlStr = this.exportBase;
  1063. // token
  1064. urlStr += `?${localStorage.getItem("auth") || ""}`;
  1065. if (this.isShowSingleData) {
  1066. // 指标id
  1067. urlStr += `&IndexCode=${
  1068. this.isShowSingleData ? this.singleDataCode : ""
  1069. }`;
  1070. // 指标名称参数
  1071. urlStr += `&IndexName=${this.select_quota}`;
  1072. /* // 指标id
  1073. urlStr+=`&IndexCode=${this.leftSearchTradeCode}` */
  1074. // 分类名称
  1075. urlStr += `&TypeName=${this.select_breed}`;
  1076. // 频度
  1077. urlStr += `&Frequency=${this.select_frequency}`;
  1078. // 单位
  1079. urlStr += `&UnitName=${this.select_Unit}`;
  1080. // 修改时间
  1081. urlStr += `&ModifyTime=${this.select_ModifyTime}`;
  1082. } else {
  1083. // 目录id
  1084. urlStr += `&ClassifyId=${
  1085. this.isShowSingleData ? "" : this.select_classify
  1086. }`;
  1087. }
  1088. return this.escapeStr(urlStr);
  1089. },
  1090. },
  1091. created() {},
  1092. mounted() {
  1093. this.getClassify();
  1094. },
  1095. };
  1096. </script>
  1097. <style lang="scss">
  1098. @import "../css/customtree.scss";
  1099. .smmTarget-dialog-cont {
  1100. .el-cascader {
  1101. .el-input {
  1102. width: 100% !important;
  1103. }
  1104. }
  1105. }
  1106. </style>
  1107. <style lang="scss" scoped>
  1108. .smmTarget-container {
  1109. display: flex;
  1110. * {
  1111. box-sizing: border-box;
  1112. }
  1113. .minHeight {
  1114. height: calc(100vh - 120px);
  1115. background-color: #fff;
  1116. box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.05);
  1117. border-radius: 4px;
  1118. }
  1119. div::-webkit-scrollbar {
  1120. width: 5px !important;
  1121. }
  1122. .left-cont {
  1123. min-width: 300px;
  1124. width: 300px;
  1125. margin-right: 20px;
  1126. padding: 30px 0;
  1127. overflow: hidden;
  1128. position: relative;
  1129. .left-top {
  1130. padding: 0 20px;
  1131. }
  1132. .scroll-wrap {
  1133. padding: 0 10px;
  1134. height: calc(100vh - 280px);
  1135. overflow-y: auto;
  1136. .target_tree {
  1137. color: #333;
  1138. .label-input .el-input__inner {
  1139. height: 25px;
  1140. line-height: 25px;
  1141. }
  1142. .custom-tree-node {
  1143. display: flex !important;
  1144. justify-content: space-between;
  1145. align-items: center;
  1146. display: block;
  1147. flex: 1;
  1148. .node_label {
  1149. margin-right: 2px;
  1150. }
  1151. .el-icon-view {
  1152. color: #409eff;
  1153. font-size: 18px;
  1154. margin-left: 5px;
  1155. }
  1156. }
  1157. }
  1158. .add-cont {
  1159. margin: 50px 0 20px;
  1160. display: flex;
  1161. align-items: center;
  1162. justify-content: center;
  1163. color: #409eff;
  1164. font-size: 16px;
  1165. cursor: pointer;
  1166. }
  1167. }
  1168. .move-btn {
  1169. height: 100%;
  1170. width: 4px;
  1171. position: absolute;
  1172. right: 0px;
  1173. top: 0;
  1174. &:hover {
  1175. cursor: col-resize;
  1176. }
  1177. }
  1178. .classify-list {
  1179. padding: 0 20px;
  1180. /* margin-top: 20px; */
  1181. height: calc(100vh - 280px);
  1182. overflow-y: auto;
  1183. .classify-item {
  1184. font-size: 14px;
  1185. color: #666;
  1186. margin-bottom: 20px;
  1187. &:hover {
  1188. cursor: pointer;
  1189. color: #409eff;
  1190. }
  1191. &.act {
  1192. color: #409eff;
  1193. }
  1194. }
  1195. }
  1196. }
  1197. .right-cont {
  1198. width: 82%;
  1199. padding: 30px;
  1200. .right-box {
  1201. max-width: 100%;
  1202. max-height: calc(100vh - 230px);
  1203. border-left: 1px solid #dcdfe6;
  1204. border-right: 1px solid #dcdfe6;
  1205. overflow: auto;
  1206. .data-header {
  1207. width: 100%;
  1208. position: sticky;
  1209. top: 0;
  1210. z-index: 2;
  1211. }
  1212. .data-cont {
  1213. height: calc(100vh - 444px);
  1214. }
  1215. .nodata {
  1216. height: calc(100vh - 460px);
  1217. border: 1px solid #dcdfe6;
  1218. font-size: 16px;
  1219. color: #999;
  1220. }
  1221. }
  1222. .frequency-list {
  1223. margin-top: 20px;
  1224. display: flex;
  1225. flex-wrap: wrap;
  1226. .frequency-btn {
  1227. width: 112px;
  1228. margin: 0 30px 10px 0;
  1229. }
  1230. }
  1231. .nodata-cont {
  1232. width: 150px !important;
  1233. text-align: center;
  1234. color: #666;
  1235. font-size: 16px;
  1236. margin: 0 auto;
  1237. }
  1238. }
  1239. }
  1240. .dialog-cont {
  1241. padding-left: 50px;
  1242. }
  1243. .dia-bot {
  1244. display: flex;
  1245. justify-content: center;
  1246. }
  1247. </style>