index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. <template>
  2. <div class="carousel">
  3. <!-- <Banner /> -->
  4. <div class="content">
  5. <byTable :source="sourceList.data" :pagination="sourceList.pagination" :config="config" :loading="loading" highlight-current-row :action-list="[
  6. {
  7. text: '添加轮播图',
  8. action: () => openModal('add'),
  9. },
  10. ]" @get-list="getList">
  11. <template #slotName="{ item }">
  12. {{ item.createTime }}
  13. </template>
  14. </byTable>
  15. </div>
  16. <el-dialog :title="modalType == 'add' ? '新增' : '编辑'" v-model="dialogVisible" width="800" v-loading="loading">
  17. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="byform">
  18. <template #carouselUrl>
  19. <el-row style="width: 100%">
  20. <el-col :span="6">
  21. <el-form-item prop="carouselUrl">
  22. <el-upload class="uploader-icon" :action="uploadUrl" :data="carouselUrlOne" :show-file-list="false" accept=".gif, .jpeg, .jpg, .png"
  23. :on-success="carouselUrlSuccess" :before-upload="uploadCarouselUrl">
  24. <el-image v-if="formData.data.carouselUrlList && formData.data.carouselUrlList.length > 0"
  25. :src="formData.data.carouselUrlList[0].fileUrl" fit="scale-down" class="avatar" />
  26. <el-icon v-else class="uploader-icon">
  27. <Plus />
  28. </el-icon>
  29. </el-upload>
  30. <el-button class="delete-btn" type="danger" v-if="formData.data.carouselUrlList && formData.data.carouselUrlList.length > 0"
  31. @click="formData.data.carouselUrlList = []">
  32. 删除
  33. </el-button>
  34. </el-form-item>
  35. </el-col>
  36. </el-row>
  37. </template>
  38. <template #menuId>
  39. <el-form-item prop="menuId">
  40. <el-select clearable v-model="formData.data.columnId" :rule="rules.columnId" placeholder="请选择菜单" no-data-text="无数据,请到栏目菜单添加"
  41. @change="(val) => getArticleListSelect(val)">
  42. <el-option v-for="item in columnListData" :label="item.name" :value="item.id">
  43. </el-option>
  44. </el-select>
  45. </el-form-item>
  46. </template>
  47. </byForm>
  48. <template #footer>
  49. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  50. <el-button type="primary" v-no-double-click="submitForm" size="large" :loading="submitLoading">确 定</el-button>
  51. </template>
  52. </el-dialog>
  53. </div>
  54. </template>
  55. <script setup>
  56. /* eslint-disable vue/no-unused-components */
  57. import { ElMessage, ElMessageBox } from "element-plus";
  58. import byTable from "@/components/byTable/index.vue";
  59. import byForm from "@/components/byForm/index.vue";
  60. import { computed, ref } from "vue";
  61. import { getDictOneByXmhjc, getFileList, getFileStr } from "@/api/XMHJC/common";
  62. import { findColumnArticleList, findMenuListByOpen } from "@/api/XMHJC/column";
  63. const loading = ref(false);
  64. const submitLoading = ref(false);
  65. const enableStatus = ref([]);
  66. const carouselModules = ref([]);
  67. const articleList = ref([]);
  68. const columnListData = ref([]);
  69. const targetType = ref([]);
  70. const sourceList = ref({
  71. data: [],
  72. pagination: {
  73. total: 3,
  74. pageNum: 1,
  75. pageSize: 10,
  76. },
  77. });
  78. let dialogVisible = ref(false);
  79. let modalType = ref("add");
  80. let rules = ref({
  81. modules: [{ required: true, message: "请选择所属模块" }],
  82. title: [{ required: true, message: "请输入标题" }],
  83. status: [{ required: true, message: "请选择启用状态", trigger: "change" }],
  84. sort: [{ required: true, message: "请输入排序", trigger: "blur" }],
  85. carouselUrl: [{ required: true, message: "请上传轮播图", trigger: "blur" }],
  86. });
  87. const { proxy } = getCurrentInstance();
  88. const config = computed(() => {
  89. return [
  90. {
  91. attrs: {
  92. label: "所属模块",
  93. prop: "modules",
  94. },
  95. render(type) {
  96. return proxy.dictValueLabel(type, carouselModules.value);
  97. },
  98. },
  99. {
  100. attrs: {
  101. label: "标题",
  102. prop: "title",
  103. },
  104. },
  105. {
  106. attrs: {
  107. label: "副标题",
  108. prop: "subTitle",
  109. },
  110. },
  111. {
  112. attrs: {
  113. label: "排序",
  114. prop: "sort",
  115. align: "center",
  116. },
  117. },
  118. {
  119. attrs: {
  120. label: "状态",
  121. prop: "status",
  122. },
  123. render(type) {
  124. return proxy.dictValueLabel(type, enableStatus.value);
  125. },
  126. },
  127. {
  128. attrs: {
  129. label: "操作",
  130. width: "200",
  131. align: "right",
  132. },
  133. // 渲染 el-button,一般用在最后一列。
  134. renderHTML(row) {
  135. return [
  136. {
  137. attrs: {
  138. label: row.status == 1 ? "禁用" : "启用",
  139. type: "primary",
  140. text: true,
  141. },
  142. el: "button",
  143. click() {
  144. changeStatus(row);
  145. },
  146. },
  147. {
  148. attrs: {
  149. label: "编辑",
  150. type: "primary",
  151. text: true,
  152. },
  153. el: "button",
  154. click() {
  155. getDetail(row);
  156. },
  157. },
  158. {
  159. attrs: {
  160. label: "删除",
  161. type: "danger",
  162. text: true,
  163. },
  164. el: "button",
  165. click() {
  166. del(row);
  167. },
  168. },
  169. ];
  170. },
  171. },
  172. ];
  173. });
  174. let formData = reactive({
  175. data: {},
  176. treeData: [],
  177. carouselUrlList: [],
  178. });
  179. const formOption = reactive({
  180. inline: true,
  181. labelWidth: 100,
  182. itemWidth: 100,
  183. rules: [],
  184. });
  185. const byform = ref(null);
  186. const formConfig = computed(() => {
  187. return [
  188. {
  189. label: "所属模块",
  190. prop: "modules",
  191. type: "select",
  192. data: carouselModules.value,
  193. clearable: true,
  194. required: true,
  195. },
  196. {
  197. type: "input",
  198. prop: "title",
  199. label: "标题",
  200. itemWidth: 100,
  201. maxlength: 10,
  202. itemType: "text",
  203. },
  204. {
  205. type: "input",
  206. prop: "subTitle",
  207. label: "副标题",
  208. maxlength: 30,
  209. },
  210. {
  211. type: "slot",
  212. slotName: "carouselUrl",
  213. prop: "carouselUrl",
  214. label: "轮播图",
  215. },
  216. {
  217. label: "跳转方式",
  218. prop: "targetType",
  219. type: "select",
  220. clearable: true,
  221. data: targetType.value,
  222. },
  223. {
  224. type: "input",
  225. prop: "url",
  226. label: "外链URL",
  227. maxlength: 100,
  228. isShow: formData.data.targetType == 2,
  229. },
  230. {
  231. type: "slot",
  232. slotName: "menuId",
  233. prop: "menuId",
  234. label: "菜单",
  235. required: true,
  236. },
  237. {
  238. label: "跳转文章",
  239. prop: "articleId",
  240. type: "select",
  241. data: articleList.value,
  242. filterable: true,
  243. clearable: true,
  244. isShow: formData.data.targetType == 1,
  245. },
  246. {
  247. label: "启用状态",
  248. prop: "status",
  249. type: "select",
  250. clearable: true,
  251. data: enableStatus.value,
  252. required: true,
  253. },
  254. {
  255. type: "input",
  256. itemType: "number",
  257. prop: "sort",
  258. label: "排序",
  259. style: {
  260. width: "50%",
  261. },
  262. },
  263. ];
  264. });
  265. const getList = async (req) => {
  266. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  267. loading.value = true;
  268. proxy
  269. .post("/carouselManager/page", sourceList.value.pagination)
  270. .then((message) => {
  271. console.log(message);
  272. sourceList.value.data = message.rows;
  273. sourceList.value.pagination.total = message.total;
  274. setTimeout(() => {
  275. loading.value = false;
  276. }, 200);
  277. });
  278. };
  279. const openModal = () => {
  280. dialogVisible.value = true;
  281. modalType.value = "add";
  282. formData.data = {};
  283. };
  284. const submitForm = () => {
  285. byform.value.handleSubmit((valid) => {
  286. submitLoading.value = true;
  287. proxy
  288. .post("/carouselManager/" + modalType.value, formData.data)
  289. .then((res) => {
  290. ElMessage({
  291. message: modalType.value == "add" ? "添加成功" : "编辑成功",
  292. type: "success",
  293. });
  294. dialogVisible.value = false;
  295. submitLoading.value = false;
  296. getList();
  297. })
  298. .catch((err) => {
  299. submitLoading.value = false;
  300. });
  301. });
  302. };
  303. const changeStatus = (row) => {
  304. modalType.value = "edit";
  305. let status = row.status == "1" ? 0 : 1;
  306. proxy.post("/carouselManager/detail", { id: row.id }).then((res) => {
  307. res.status = status;
  308. formData.data = res;
  309. ElMessageBox.confirm("你是否确认此操作?", "提示", {
  310. confirmButtonText: "确定",
  311. cancelButtonText: "取消",
  312. type: "warning",
  313. }).then(() => {
  314. // 更新状态
  315. proxy
  316. .post("/carouselManager/" + modalType.value, formData.data)
  317. .then((res) => {
  318. ElMessage({
  319. message: "操作成功",
  320. type: "success",
  321. });
  322. getList();
  323. });
  324. });
  325. });
  326. };
  327. //编辑详情
  328. const getDetail = (row) => {
  329. modalType.value = "edit";
  330. proxy.post("/carouselManager/detail", { id: row.id }).then((res) => {
  331. formData.data = res;
  332. getFileList({ businessIdList: [res.id], fileType: 1 }).then((resFile) => {
  333. formData.data.carouselUrlList = resFile.data[res.id];
  334. formData.data.carouselUrl = resFile.data[res.id];
  335. dialogVisible.value = true;
  336. });
  337. getArticleList(formData.data.columnId)
  338. });
  339. };
  340. //删除
  341. const del = (row) => {
  342. modalType.value = "edit";
  343. ElMessageBox.confirm("你是否确认此操作?", "提示", {
  344. confirmButtonText: "确定",
  345. cancelButtonText: "取消",
  346. type: "warning",
  347. }).then(() => {
  348. proxy.post("/carouselManager/delete", { id: row.id }).then((res) => {
  349. ElMessage({
  350. message: "操作成功",
  351. type: "success",
  352. });
  353. getList();
  354. });
  355. });
  356. };
  357. //获取字典
  358. const getDictlist = async () => {
  359. const res = await getDictOneByXmhjc([
  360. "enable_status",
  361. "carousel_modules",
  362. "carousel_target_type",
  363. ]);
  364. enableStatus.value = res["enable_status"].map((x) => ({
  365. label: x.dictValue,
  366. value: x.dictKey,
  367. }));
  368. carouselModules.value = res["carousel_modules"].map((x) => ({
  369. label: x.dictValue,
  370. value: x.dictKey,
  371. }));
  372. targetType.value = res["carousel_target_type"].map((x) => ({
  373. label: x.dictValue,
  374. value: x.dictKey,
  375. }));
  376. };
  377. //获取文章列表
  378. const getArticleListSelect = async (value) => {
  379. formData.data.articleId = "";
  380. await getArticleList(value);
  381. };
  382. //获取文章列表
  383. const getArticleList = async (value) => {
  384. const res = await findColumnArticleList({
  385. pageNum: 1,
  386. pageSize: 99999,
  387. status: 1,
  388. columnId: value,
  389. });
  390. articleList.value = res.data.rows.map((x) => ({
  391. label: x.title,
  392. value: x.id,
  393. }));
  394. };
  395. //图片上传相关
  396. const carouselUrlOne = ref({});
  397. const uploadCarouselUrl = async (file) => {
  398. const res = await getFileStr({ fileName: file.name });
  399. carouselUrlOne.value = res.data.uploadBody;
  400. file.id = res.data.id;
  401. file.fileName = res.data.fileName;
  402. file.fileUrl = res.data.fileUrl;
  403. return true;
  404. };
  405. const carouselUrlSuccess = (response, uploadFile) => {
  406. formData.data.carouselUrlList = [
  407. {
  408. id: uploadFile.raw.id,
  409. fileName: uploadFile.raw.fileName,
  410. fileUrl: uploadFile.raw.fileUrl,
  411. },
  412. ];
  413. formData.data.carouselUrl = uploadFile.raw.fileUrl;
  414. };
  415. const getMenuList = async () => {
  416. const res = await findMenuListByOpen({});
  417. columnListData.value = res.data;
  418. };
  419. getMenuList();
  420. getList();
  421. getDictlist();
  422. </script>
  423. <style lang="scss" scoped>
  424. .tenant {
  425. padding: 20px;
  426. }
  427. .el-icon.uploader-icon {
  428. font-size: 28px;
  429. color: #8c939d;
  430. width: 110px;
  431. height: 110px;
  432. text-align: center;
  433. border: 1px dashed var(--el-border-color);
  434. }
  435. </style>