lableManage.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. <script setup>
  2. import { ref, onMounted } from "vue";
  3. import Sortable from "sortablejs";
  4. import mPage from "@/components/mPage.vue";
  5. import { raiInterface } from "@/api/api.js";
  6. import LableDlg from "./components/lableDlg.vue";
  7. import { ElMessage,ElMessageBox } from "element-plus";
  8. const labelForm = ref({
  9. TagName: "",
  10. ArticleTypes: "", //关联的报告系列
  11. ActivityTypes: [],
  12. Industries: "", //关联产业列表
  13. SubjectNames: "",
  14. });
  15. const rules = ref({
  16. TagName: [{ required: true, message: "请输入标签名称", trigger: "blur" }],
  17. });
  18. const dialogVisible = ref(false);
  19. const tableSelect = ref([
  20. {
  21. name: "当前标签数据",
  22. value: 1,
  23. },
  24. {
  25. name: "已撤下的标签",
  26. value: 0,
  27. },
  28. ]);
  29. const page_no = ref(1);
  30. const total = ref(0);
  31. const pageSize = ref(10);
  32. const lableList = ref([]);
  33. const tableList = ref([]);
  34. // 获取表格列表
  35. async function getDataList() {
  36. const res = await raiInterface.getLableTagList({
  37. Status: tableSelectActive.value,
  38. PageSize: pageSize.value,
  39. CurrentIndex: page_no.value,
  40. SortParam: "pv",
  41. SortType: sortType.value,
  42. });
  43. if (res.Ret === 200) {
  44. total.value = res.Data.Paging.Totals;
  45. tableList.value = res.Data.List || [];
  46. }
  47. }
  48. // 获取标签列表
  49. async function getLableTagList() {
  50. const res = await raiInterface.getLableTagListCustom();
  51. if (res.Ret === 200) {
  52. lableList.value = res.Data || [];
  53. }
  54. }
  55. // 获取活动类型
  56. async function activityType() {
  57. const res = await raiInterface.getActivityType({
  58. IsGetAll: true,
  59. });
  60. if (res.Ret === 200) {
  61. optionsActivity.value = res.Data.List;
  62. }
  63. }
  64. // 表格的切换点击事件
  65. function tableSelectHandel(item) {
  66. if (tableSelectActive.value !== item.value) {
  67. page_no.value = 1;
  68. tableSelectActive.value = item.value;
  69. getDataList();
  70. }
  71. }
  72. // 重新上线 // 撤下标签
  73. function lableButtonHandel(type, item) {
  74. ElMessageBox.confirm(type == "撤下" ? "确定要撤下此标签吗?" : "确定要重新上线此标签吗?", "提示", {
  75. confirmButtonText: "确定",
  76. cancelButtonText: "取消",
  77. type: "warning",
  78. })
  79. .then(async () => {
  80. const res = await raiInterface.getLableTagEnable({
  81. Status: item.Status == 0 ? 1 : 0,
  82. TagId: item.TagId,
  83. });
  84. if (res.Ret === 200) {
  85. getLableTagList();
  86. getDataList();
  87. ElMessage({
  88. type: "success",
  89. message: "操作成功!",
  90. });
  91. }
  92. })
  93. .catch(() => {
  94. ElMessage({
  95. type: "info",
  96. message: "已取消",
  97. });
  98. });
  99. }
  100. // 分页的事件
  101. function handleCurrentChange(page) {
  102. page_no.value = page;
  103. getDataList();
  104. }
  105. const tableSelectActive = ref(1);
  106. const optionsSubject = ref([]);
  107. const dlgTitle = ref("添加");
  108. const showRegularDlg = ref(false);
  109. const dataRegular = ref({});
  110. const sortType = ref("");
  111. const lableSortable = ref(null);
  112. // 拖拽的事件
  113. function setupSortable() {
  114. const sortableInstanceIs = Sortable.create(lableSortable.value, {
  115. ghostClass: "sortable-ghost", // drop placeholder的css类名
  116. sort: true,
  117. onEnd(obj) {
  118. const { newIndex, oldIndex } = obj;
  119. // const newList = _.cloneDeep(lableList.value);
  120. const newList = lableList.value;
  121. let PrevTagId = 0;
  122. let NextTagId = 0;
  123. if (newIndex === 0) {
  124. PrevTagId = 0;
  125. NextTagId = newList[newIndex].TagId;
  126. } else if (newIndex === newList.length - 1) {
  127. PrevTagId = newList[newIndex].TagId;
  128. NextTagId = 0;
  129. } else {
  130. if (newIndex > oldIndex) {
  131. NextTagId = newList[newIndex + 1].TagId;
  132. PrevTagId = newList[newIndex].TagId;
  133. } else {
  134. NextTagId = newList[newIndex].TagId;
  135. PrevTagId = newList[newIndex - 1].TagId;
  136. }
  137. }
  138. let params = {
  139. TagId: newList[oldIndex].TagId,
  140. PrevTagId,
  141. NextTagId,
  142. };
  143. postLableTagMove(params);
  144. },
  145. });
  146. }
  147. // 拖拽的事件
  148. async function postLableTagMove(params) {
  149. const res = await raiInterface.postLableTagMove(params);
  150. if (res.Ret === 200) {
  151. getLableTagList();
  152. getDataList();
  153. ElMessage.success("移动成功");
  154. }
  155. }
  156. // 添加或者编辑标签
  157. function addOfEitdHandler(type, item) {
  158. if (item && item.TagType > 0) {
  159. dataRegular.value = item;
  160. showRegularDlg.value = true;
  161. return;
  162. }
  163. dlgTitle.value = type;
  164. if (item) {
  165. const { TagName, ArticleTypes, ActivityTypes, Industries, SubjectNames, TagId } = item;
  166. labelForm.value.TagName = TagName;
  167. labelForm.value.ArticleTypes = ArticleTypes ? ArticleTypes.split(",") : [];
  168. labelForm.value.ActivityTypes = ActivityTypes ? ActivityTypes.split(",") : [];
  169. labelForm.value.Industries = Industries ? Industries.split(",") : [];
  170. labelForm.value.SubjectNames = SubjectNames ? SubjectNames.split(",") : [];
  171. labelForm.value.TagId = TagId;
  172. }
  173. dialogVisible.value = true;
  174. }
  175. // pv uv 下载
  176. function exportPvUv(id) {
  177. const url = import.meta.env.VITE_APP_API_ROOT + `/cygx/tag/PvExport?TagId=${id}&${localStorage.getItem("auth") || ""}`;
  178. return url;
  179. }
  180. // 添加标签
  181. function addTagHandler() {
  182. ruleForm.value.validate(async (valid) => {
  183. if (valid) {
  184. let { ArticleTypes, ActivityTypes, Industries, SubjectNames } = labelForm.value;
  185. if (!ArticleTypes.length && !ActivityTypes.length && !SubjectNames.length && !Industries.length) return ElMessage.error("请至少填写一个关联项");
  186. let params = {
  187. TagName: labelForm.value.TagName,
  188. ArticleTypes: ArticleTypes ? ArticleTypes.join(",") : "",
  189. ActivityTypes: ActivityTypes ? ActivityTypes.join(",") : "",
  190. Industries: Industries ? Industries.join(",") : "",
  191. SubjectNames: SubjectNames ? SubjectNames.join(",") : "",
  192. TagId: dlgTitle.value == "添加" ? 0 : labelForm.value.TagId,
  193. };
  194. const res = await raiInterface.postLableTagSave(params);
  195. if (res.Ret === 200) {
  196. handleClose();
  197. getLableTagList();
  198. getDataList();
  199. ElMessage.success("操作成功");
  200. }
  201. } else {
  202. console.log("error submit!!");
  203. return false;
  204. }
  205. });
  206. }
  207. const optionsArticle = ref([]);
  208. const optionsActivity = ref([]);
  209. const optionsIndustries = ref([]);
  210. // 关闭弹框
  211. function handleClose() {
  212. optionsArticle.value = [];
  213. optionsIndustries.value = [];
  214. optionsSubject.value = [];
  215. labelForm.value = {
  216. TagName: "",
  217. ArticleTypes: "", //关联的报告系列
  218. ActivityTypes: [],
  219. Industries: "", //关联产业列表
  220. SubjectNames: "",
  221. };
  222. dialogVisible.value = false;
  223. ruleForm.value.resetFields();
  224. }
  225. const ruleForm = ref(null);
  226. // 搜索所有的报告系列
  227. async function remoteMethodArticle(query) {
  228. if (query !== "") {
  229. const res = await raiInterface.getLableTagSubCategoryName({
  230. KeyWord: query,
  231. });
  232. if (res.Ret === 200) {
  233. optionsArticle.value = res.Data || [];
  234. }
  235. } else {
  236. optionsArticle.value = [];
  237. }
  238. }
  239. // 产业
  240. async function remoteMethodIndustries(query) {
  241. if (query !== "") {
  242. const res = await raiInterface.getLableTagIndustrialManagement({
  243. KeyWord: query,
  244. });
  245. if (res.Ret === 200) {
  246. optionsIndustries.value = res.Data.List || [];
  247. }
  248. } else {
  249. optionsIndustries.value = [];
  250. }
  251. }
  252. // 标的
  253. async function remoteMethodSubject(query) {
  254. if (query !== "") {
  255. const res = await raiInterface.industrialSubjectSearch({
  256. KeyWord: query,
  257. });
  258. if (res.Ret === 200) {
  259. optionsSubject.value = res.Data.List || [];
  260. }
  261. } else {
  262. optionsSubject.value = [];
  263. }
  264. }
  265. function sortChangeHandle(column) {
  266. sortType.value = column.order == "descending" ? "desc" : column.order == "ascending" ? "asc" : "";
  267. getDataList();
  268. }
  269. onMounted(() => {
  270. setupSortable();
  271. getDataList();
  272. getLableTagList();
  273. activityType();
  274. });
  275. </script>
  276. <template>
  277. <div class="container lable-manage-page">
  278. <el-card style="overflow: hidden">
  279. <div class="top-comtent">
  280. <div>
  281. <span>当前标签</span>
  282. <span>自定义标签</span>
  283. <span>固定标签</span>
  284. </div>
  285. <el-button type="primary" @click="addOfEitdHandler('添加')">添加标签</el-button>
  286. </div>
  287. <div ref="lableSortable" class="lable-content">
  288. <div :class="['lable-item', item.TagType > 0 && 'regular-lable']" v-for="item in lableList" :key="item.TagId">
  289. <div class="text_oneLine">{{ item.TagName }}</div>
  290. <div class="lable-img" v-if="item.TagType">
  291. <img src="~@/assets/img/rai_m/edit_icon_GuDing.png" alt="" @click="addOfEitdHandler('编辑', item)" />
  292. <img src="~@/assets/img/rai_m/remove_below_GuDing.png" alt="" @click="lableButtonHandel('撤下', item)" />
  293. </div>
  294. <div class="lable-img" v-else>
  295. <img src="~@/assets/img/rai_m/edit_icon.png" alt="" @click="addOfEitdHandler('编辑', item)" />
  296. <img src="~@/assets/img/rai_m/remove_below.png" alt="" @click="lableButtonHandel('撤下', item)" />
  297. </div>
  298. </div>
  299. </div>
  300. </el-card>
  301. <el-card style="margin-top: 20px">
  302. <div class="lable-select-box">
  303. <div v-for="(item, index) in tableSelect" :key="item.value" @click="tableSelectHandel(item)" class="item">
  304. <span :class="['name', tableSelectActive == item.value && 'active']">{{ item.name }}</span>
  305. <span v-if="index == 0" class="divide">|</span>
  306. </div>
  307. </div>
  308. <el-table border :data="tableList" @sort-change="sortChangeHandle">
  309. <el-table-column align="center" key="name" prop="TagName" label="标签名称" width=""></el-table-column>
  310. <el-table-column align="center" key="series" prop="ArticleTypes" label="报告类型" width=""></el-table-column>
  311. <el-table-column align="center" key="type" prop="ActivityTypes" label="活动类型" width=""></el-table-column>
  312. <el-table-column align="center" key="industry" prop="Industries" label="相关产业" width=""></el-table-column>
  313. <el-table-column align="center" key="subject" prop="SubjectNames" label="相关标的" width=""></el-table-column>
  314. <el-table-column align="center" key="tiem" prop="OnlineTime" label="上线时间" width="180"></el-table-column>
  315. <el-table-column align="center" key="remove" prop="OfflineTime" label="撤下时间" width="180" v-if="tableSelectActive == 0"></el-table-column>
  316. <el-table-column align="center" key="pvuv" prop="Sort" label="pv/uv" width="90" sortable="custom">
  317. <template #default="{ row }">
  318. <div class="pv-uv-download">
  319. <span>{{ row.Pv }}/{{ row.Uv }}</span>
  320. <a :href="exportPvUv(row.TagId)" download>
  321. <img src="~@/assets/img/rai_m/pvuv_download.png" alt="" />
  322. </a>
  323. </div>
  324. </template>
  325. </el-table-column>
  326. <el-table-column align="center" key="operate" label="操作" width="125" v-if="tableSelectActive == 0">
  327. <template #default="{ row }">
  328. <span class="editsty" @click="lableButtonHandel('上线', row)">重新上线 &nbsp;&nbsp;</span>
  329. </template>
  330. </el-table-column>
  331. </el-table>
  332. <el-col :span="24" class="toolbar">
  333. <m-page :total="total" :page_no="page_no" @handleCurrentChange="handleCurrentChange" />
  334. </el-col>
  335. </el-card>
  336. <div>
  337. <el-dialog :title="dlgTitle" @close="handleClose" v-model="dialogVisible" width="566px" :close-on-click-modal="false" :modal-append-to-body="false">
  338. <div>
  339. <el-form :model="labelForm" :rules="rules" ref="ruleForm" class="demo-ruleForm">
  340. <el-form-item prop="TagName">
  341. <el-input style="width: 100%" :maxlength="8" v-model="labelForm.TagName" placeholder="请输入标签名称(8个字以内)"></el-input>
  342. </el-form-item>
  343. <el-form-item>
  344. <el-select
  345. style="width: 100%"
  346. v-model="labelForm.ArticleTypes"
  347. multiple
  348. filterable
  349. remote
  350. reserve-keyword
  351. placeholder="请输入关联的报告类型(选填,可输入多个)"
  352. :remote-method="remoteMethodArticle"
  353. >
  354. <el-option v-for="item in optionsArticle" :key="item.SubCategoryName" :label="item.SubCategoryName" :value="item.SubCategoryName"> </el-option>
  355. </el-select>
  356. </el-form-item>
  357. <el-form-item>
  358. <el-select style="width: 100%" multiple v-model="labelForm.ActivityTypes" placeholder="请输入关联的活动类型(选填,可输入多个)">
  359. <el-option v-for="item in optionsActivity" :label="item.ActivityTypeName" :key="item.ActivityTypeName" :value="item.ActivityTypeName"></el-option
  360. ></el-select>
  361. </el-form-item>
  362. <el-form-item>
  363. <el-select
  364. style="width: 100%"
  365. v-model="labelForm.Industries"
  366. multiple
  367. filterable
  368. remote
  369. reserve-keyword
  370. placeholder="请输入相关产业(选填,可输入多个)"
  371. :remote-method="remoteMethodIndustries"
  372. >
  373. <el-option v-for="item in optionsIndustries" :key="item.IndustryName" :label="item.IndustryName" :value="item.IndustryName"> </el-option>
  374. </el-select>
  375. </el-form-item>
  376. <el-form-item>
  377. <el-select
  378. style="width: 100%"
  379. v-model="labelForm.SubjectNames"
  380. multiple
  381. filterable
  382. remote
  383. reserve-keyword
  384. placeholder="请输入相关标的(选填,可输入多个)"
  385. :remote-method="remoteMethodSubject"
  386. >
  387. <el-option v-for="item in optionsSubject" :key="item.SubjectName" :label="item.SubjectName" :value="item.SubjectName"> </el-option>
  388. </el-select>
  389. </el-form-item>
  390. </el-form>
  391. </div>
  392. <template #footer>
  393. <span class="dialog-footer">
  394. <el-button @click="handleClose">取 消</el-button>
  395. <el-button type="primary" @click="addTagHandler">确 定</el-button>
  396. </span>
  397. </template>
  398. </el-dialog>
  399. </div>
  400. <lable-dlg :showRegularDlg="showRegularDlg" :dataRegular="dataRegular" />
  401. </div>
  402. </template>
  403. <style scoped lang="scss">
  404. .lable-manage-page {
  405. .top-comtent {
  406. display: flex;
  407. align-items: center;
  408. justify-content: space-between;
  409. div {
  410. :nth-child(2),
  411. :nth-child(3) {
  412. font-size: 12px;
  413. font-weight: 400;
  414. text-align: center;
  415. display: inline-block;
  416. width: 80px;
  417. height: 30px;
  418. line-height: 30px;
  419. background: #ecf5ff;
  420. border: 1px solid #b3d8ff;
  421. color: #409eff;
  422. border-radius: 4px;
  423. margin-left: 10px;
  424. }
  425. :nth-child(3) {
  426. background-color: #fff8e4;
  427. border: 1px solid #ffd9c2;
  428. color: #e37318;
  429. }
  430. }
  431. span {
  432. font-weight: 500;
  433. font-size: 16px;
  434. }
  435. }
  436. .lable-content {
  437. display: flex;
  438. flex-wrap: wrap;
  439. padding: 30px 0;
  440. width: 105%;
  441. .lable-item {
  442. display: flex;
  443. align-items: center;
  444. justify-content: space-between;
  445. width: 205px;
  446. height: 40px;
  447. background: #ecf5ff;
  448. border: 1px solid #b3d8ff;
  449. color: #409eff;
  450. border-radius: 4px;
  451. margin: 0 30px 20px 0;
  452. padding: 0 10px;
  453. cursor: move;
  454. box-sizing: border-box;
  455. .lable-img {
  456. width: 38px;
  457. flex-shrink: 0;
  458. display: flex;
  459. justify-content: space-between;
  460. cursor: pointer;
  461. img {
  462. width: 14px;
  463. height: 14px;
  464. }
  465. }
  466. }
  467. .sortable-ghost {
  468. width: 100px;
  469. height: 1px;
  470. border: 2px solid #409eff;
  471. overflow: hidden;
  472. }
  473. .regular-lable {
  474. background-color: #fff8e4 !important;
  475. border: 1px solid #ffd9c2;
  476. color: #e37318;
  477. }
  478. }
  479. .pv-uv-download {
  480. display: flex;
  481. align-items: center;
  482. justify-content: center;
  483. img {
  484. width: 14px;
  485. height: 14px;
  486. margin-left: 10px;
  487. }
  488. }
  489. .lable-select-box {
  490. display: flex;
  491. margin-bottom: 20px;
  492. .item {
  493. display: flex;
  494. line-height: 40px;
  495. cursor: pointer;
  496. .name {
  497. width: 120px;
  498. height: 40px;
  499. text-align: center;
  500. }
  501. .divide {
  502. padding: 0 20px;
  503. }
  504. }
  505. .active {
  506. background: #409eff;
  507. border-radius: 4px;
  508. color: #fff;
  509. }
  510. }
  511. }
  512. </style>