index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. <template>
  2. <basic-container>
  3. <avue-crud :option="option" :table-loading="loading" :data="data" :page.sync="page" ref="crud" @row-del="rowDel"
  4. v-model="form" :permission="permissionList" @row-update="rowUpdate" @row-save="rowSave"
  5. :before-open="beforeOpen" @search-change="searchChange" @search-reset="searchReset"
  6. @selection-change="selectionChange" @current-change="currentChange" @size-change="sizeChange"
  7. @refresh-change="refreshChange" @on-load="onLoad">
  8. <template slot="menuLeft">
  9. <el-button type="danger" size="small" icon="el-icon-delete" plain v-if="permission.announcement_delete"
  10. @click="handleDelete">删 除
  11. </el-button>
  12. </template>
  13. <template slot-scope="{row}" slot="dealer">
  14. <el-tag>{{ row.dealerName }}</el-tag>
  15. </template>
  16. <template slot-scope="{row}" slot="brand">
  17. <el-tag>{{ row.brandName }}</el-tag>
  18. </template>
  19. <template slot-scope="{row}" slot="detail">
  20. <el-button type="text" @click="viewDetail(row)">查看详情</el-button>
  21. </template>
  22. </avue-crud>
  23. <!-- 详情查看对话框 -->
  24. <el-dialog title="公告详情" :visible.sync="detailVisible" width="60%" append-to-body>
  25. <div class="detail-content">
  26. <h3>{{ currentDetail.title }}</h3>
  27. <div class="detail-info">
  28. <p><strong>发布时间:</strong>{{ currentDetail.publishTime }}</p>
  29. <p><strong>经销商:</strong>{{ currentDetail.dealerName }}</p>
  30. <p><strong>品牌:</strong>{{ currentDetail.brandName }}</p>
  31. </div>
  32. <div class="detail-body" v-html="currentDetail.content"></div>
  33. </div>
  34. <span slot="footer" class="dialog-footer">
  35. <el-button @click="detailVisible = false">关 闭</el-button>
  36. </span>
  37. </el-dialog>
  38. </basic-container>
  39. </template>
  40. <script>
  41. import { getList, remove, update, add, getAnnouncement, getDealerList, getBrandList, getCategoryList } from "@/api/announcement";
  42. import { mapGetters } from "vuex";
  43. export default {
  44. name: 'AnnouncementIndex',
  45. data() {
  46. return {
  47. form: {},
  48. query: {},
  49. loading: true,
  50. detailVisible: false,
  51. currentDetail: {},
  52. page: {
  53. pageSize: 10,
  54. currentPage: 1,
  55. total: 0
  56. },
  57. selectionList: [],
  58. dealerOptions: [],
  59. brandOptions: [],
  60. categoryOptions: [], // 添加分类选项数组
  61. option: {
  62. height: 'auto',
  63. calcHeight: 30,
  64. dialogWidth: 950,
  65. tip: false,
  66. searchShow: true,
  67. searchMenuSpan: 6,
  68. border: true,
  69. index: true,
  70. viewBtn: true,
  71. selection: true,
  72. excelBtn: false, // 隐藏下载按钮
  73. columnBtn: false, // 隐藏列设置按钮
  74. dialogClickModal: false,
  75. column: [
  76. {
  77. label: "公告标题",
  78. prop: "title",
  79. span: 12,
  80. search: true,
  81. overHidden: true,
  82. rules: [{
  83. required: true,
  84. message: "请输入公告标题",
  85. trigger: "blur"
  86. }]
  87. },
  88. {
  89. label: "客户编号",
  90. prop: "customerCode",
  91. span: 12,
  92. search: true,
  93. overHidden: true,
  94. rules: [{
  95. required: true,
  96. message: "请输入客户编号",
  97. trigger: "blur"
  98. }]
  99. },
  100. {
  101. label: "发布时间",
  102. prop: "publishTime",
  103. type: "daterange",
  104. format: "yyyy-MM-dd",
  105. valueFormat: "yyyy-MM-dd",
  106. rangeSeparator: "至",
  107. startPlaceholder: "开始时间",
  108. endPlaceholder: "结束时间",
  109. overHidden: true,
  110. search: true,
  111. hide: true, // 在表格中隐藏,只用于搜索
  112. addDisplay: false, // 新增时不显示
  113. editDisplay: false, // 编辑时不显示
  114. viewDisplay: false // 查看时不显示
  115. },
  116. {
  117. label: "经销商",
  118. prop: "dealerId",
  119. type: "select",
  120. dicData: [],
  121. props: {
  122. label: "dealerName",
  123. value: "id"
  124. },
  125. slot: true,
  126. overHidden: true,
  127. search: true,
  128. span: 12,
  129. rules: [{
  130. required: true,
  131. message: "请选择经销商",
  132. trigger: "change"
  133. }]
  134. },
  135. {
  136. label: "品牌",
  137. prop: "brandId",
  138. type: "select",
  139. dicData: [],
  140. props: {
  141. label: "brandName",
  142. value: "id"
  143. },
  144. slot: true,
  145. overHidden: true,
  146. search: true,
  147. span: 12,
  148. rules: [{
  149. required: true,
  150. message: "请选择品牌",
  151. trigger: "change"
  152. }]
  153. },
  154. {
  155. label: "分类",
  156. prop: "categoryId",
  157. type: "select",
  158. dicData: [], // 初始为空,通过loadCategoryOptions方法动态加载
  159. props: {
  160. label: "categoryName", // 根据后端返回的字段名调整
  161. value: "id"
  162. },
  163. search: true,
  164. span: 12,
  165. rules: [{
  166. required: true,
  167. message: "请选择分类",
  168. trigger: "change"
  169. }]
  170. },
  171. {
  172. label: "角色",
  173. prop: "roleType",
  174. type: "select",
  175. dicData: [
  176. { label: "工厂", value: "factory" },
  177. { label: "经销商", value: "dealer" },
  178. { label: "零售商", value: "retailer" }
  179. ],
  180. search: true,
  181. span: 12,
  182. rules: [{
  183. required: true,
  184. message: "请选择角色",
  185. trigger: "change"
  186. }]
  187. },
  188. {
  189. label: "公告内容",
  190. prop: "content",
  191. component: 'AvueUeditor',
  192. options: {
  193. action: '/api/blade-resource/oss/endpoint/put-file',
  194. props: {
  195. res: "data",
  196. url: "link",
  197. }
  198. },
  199. showColumn: false,
  200. hide: true,
  201. minRows: 6,
  202. span: 24,
  203. rules: [{
  204. required: true,
  205. message: "请输入公告内容",
  206. trigger: "blur"
  207. }]
  208. },
  209. {
  210. label: "状态",
  211. prop: "status",
  212. type: "select",
  213. dicData: [
  214. { label: "启用", value: 1 },
  215. { label: "禁用", value: 0 }
  216. ],
  217. search: true,
  218. span: 12,
  219. value: 1
  220. }
  221. ]
  222. },
  223. data: []
  224. };
  225. },
  226. computed: {
  227. ...mapGetters(["permission"]),
  228. permissionList() {
  229. return {
  230. // addBtn: this.vaildData(this.permission.announcement_add, false),
  231. // viewBtn: this.vaildData(this.permission.announcement_view, false),
  232. // delBtn: this.vaildData(this.permission.announcement_delete, false),
  233. // editBtn: this.vaildData(this.permission.announcement_edit, false)
  234. addBtn: true,
  235. viewBtn: true,
  236. delBtn: true,
  237. editBtn: true
  238. };
  239. },
  240. ids() {
  241. let ids = [];
  242. this.selectionList.forEach(ele => {
  243. ids.push(ele.id);
  244. });
  245. return ids.join(",");
  246. }
  247. },
  248. created() {
  249. this.loadDealerOptions();
  250. this.loadBrandOptions();
  251. this.loadCategoryOptions(); // 添加分类加载
  252. },
  253. methods: {
  254. // 加载分类选项
  255. loadCategoryOptions() {
  256. getCategoryList().then(res => {
  257. this.categoryOptions = res.data.data || [];
  258. const categoryColumn = this.option.column.find(col => col.prop === 'categoryId');
  259. if (categoryColumn) {
  260. categoryColumn.dicData = this.categoryOptions;
  261. }
  262. }).catch(() => {
  263. // 如果接口不存在,使用模拟数据
  264. this.categoryOptions = [
  265. { id: 1, categoryName: '系统公告', value: 1, label: '系统公告' },
  266. { id: 2, categoryName: '产品公告', value: 2, label: '产品公告' },
  267. { id: 3, categoryName: '活动公告', value: 3, label: '活动公告' },
  268. { id: 4, categoryName: '维护公告', value: 4, label: '维护公告' }
  269. ];
  270. const categoryColumn = this.option.column.find(col => col.prop === 'categoryId');
  271. if (categoryColumn) {
  272. categoryColumn.dicData = this.categoryOptions;
  273. }
  274. });
  275. },
  276. // 查看详情
  277. viewDetail(row) {
  278. this.currentDetail = row;
  279. this.detailVisible = true;
  280. },
  281. // 加载经销商选项
  282. loadDealerOptions() {
  283. getDealerList().then(res => {
  284. this.dealerOptions = res.data.data || [];
  285. const dealerColumn = this.option.column.find(col => col.prop === 'dealerId');
  286. if (dealerColumn) {
  287. dealerColumn.dicData = this.dealerOptions;
  288. }
  289. }).catch(() => {
  290. // 如果接口不存在,使用模拟数据
  291. this.dealerOptions = [
  292. { id: 1, dealerName: '经销商A' },
  293. { id: 2, dealerName: '经销商B' },
  294. { id: 3, dealerName: '经销商C' }
  295. ];
  296. const dealerColumn = this.option.column.find(col => col.prop === 'dealerId');
  297. if (dealerColumn) {
  298. dealerColumn.dicData = this.dealerOptions;
  299. }
  300. });
  301. },
  302. // 加载品牌选项
  303. loadBrandOptions() {
  304. getBrandList().then(res => {
  305. this.brandOptions = res.data.data || [];
  306. const brandColumn = this.option.column.find(col => col.prop === 'brandId');
  307. if (brandColumn) {
  308. brandColumn.dicData = this.brandOptions;
  309. }
  310. }).catch(() => {
  311. // 如果接口不存在,使用模拟数据
  312. this.brandOptions = [
  313. { id: 1, brandName: '品牌A' },
  314. { id: 2, brandName: '品牌B' },
  315. { id: 3, brandName: '品牌C' }
  316. ];
  317. const brandColumn = this.option.column.find(col => col.prop === 'brandId');
  318. if (brandColumn) {
  319. brandColumn.dicData = this.brandOptions;
  320. }
  321. });
  322. },
  323. rowSave(row, done, loading) {
  324. add(row).then(() => {
  325. this.onLoad(this.page);
  326. this.$message({
  327. type: "success",
  328. message: "操作成功!"
  329. });
  330. done();
  331. }, error => {
  332. console.log(error);
  333. loading();
  334. });
  335. },
  336. rowUpdate(row, index, done, loading) {
  337. update(row).then(() => {
  338. this.onLoad(this.page);
  339. this.$message({
  340. type: "success",
  341. message: "操作成功!"
  342. });
  343. done();
  344. }, error => {
  345. console.log(error);
  346. loading();
  347. });
  348. },
  349. rowDel(row) {
  350. this.$confirm("确定将选择数据删除?", {
  351. confirmButtonText: "确定",
  352. cancelButtonText: "取消",
  353. type: "warning"
  354. })
  355. .then(() => {
  356. return remove(row.id);
  357. })
  358. .then(() => {
  359. this.onLoad(this.page);
  360. this.$message({
  361. type: "success",
  362. message: "操作成功!"
  363. });
  364. });
  365. },
  366. searchReset() {
  367. this.query = {};
  368. this.onLoad(this.page);
  369. },
  370. searchChange(params, done) {
  371. this.query = params;
  372. this.page.currentPage = 1;
  373. this.onLoad(this.page, params);
  374. done();
  375. },
  376. selectionChange(list) {
  377. this.selectionList = list;
  378. },
  379. selectionClear() {
  380. this.selectionList = [];
  381. this.$refs.crud.toggleSelection();
  382. },
  383. handleDelete() {
  384. if (this.selectionList.length === 0) {
  385. this.$message.warning("请选择至少一条数据");
  386. return;
  387. }
  388. this.$confirm("确定将选择数据删除?", {
  389. confirmButtonText: "确定",
  390. cancelButtonText: "取消",
  391. type: "warning"
  392. })
  393. .then(() => {
  394. return remove(this.ids);
  395. })
  396. .then(() => {
  397. this.onLoad(this.page);
  398. this.$message({
  399. type: "success",
  400. message: "操作成功!"
  401. });
  402. this.$refs.crud.toggleSelection();
  403. });
  404. },
  405. beforeOpen(done, type) {
  406. if (["edit", "view"].includes(type)) {
  407. getAnnouncement(this.form.id).then(res => {
  408. this.form = res.data.data;
  409. });
  410. }
  411. done();
  412. },
  413. currentChange(currentPage) {
  414. this.page.currentPage = currentPage;
  415. },
  416. sizeChange(pageSize) {
  417. this.page.pageSize = pageSize;
  418. },
  419. refreshChange() {
  420. this.onLoad(this.page, this.query);
  421. },
  422. onLoad(page, params = {}) {
  423. const { publishTime } = this.query;
  424. let values = {
  425. ...params,
  426. };
  427. if (publishTime) {
  428. values = {
  429. ...params,
  430. publishTimeStart: publishTime[0],
  431. publishTimeEnd: publishTime[1],
  432. ...this.query
  433. };
  434. values.publishTime = null;
  435. }
  436. this.loading = true;
  437. getList(page.currentPage, page.pageSize, values).then(res => {
  438. const data = res.data.data;
  439. this.page.total = data.total;
  440. this.data = data.records;
  441. this.loading = false;
  442. this.selectionClear();
  443. });
  444. }
  445. }
  446. };
  447. </script>
  448. <style scoped>
  449. .detail-content {
  450. padding: 20px;
  451. }
  452. .detail-info {
  453. margin: 20px 0;
  454. padding: 15px;
  455. background-color: #f5f5f5;
  456. border-radius: 4px;
  457. }
  458. .detail-info p {
  459. margin: 8px 0;
  460. }
  461. .detail-body {
  462. margin-top: 20px;
  463. padding: 15px;
  464. border: 1px solid #e4e7ed;
  465. border-radius: 4px;
  466. min-height: 200px;
  467. }
  468. </style>