You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

471 lines
14 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. <template>
  2. <el-card class="categoryContainer">
  3. <el-form :inline="true">
  4. <el-form-item label="分类名称">
  5. <el-input
  6. v-model="queryParams.title"
  7. placeholder="请输入分类名称"
  8. clearable
  9. size="small"
  10. @keyup.enter.native="handleQuery"
  11. />
  12. </el-form-item>
  13. <el-form-item>
  14. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  15. <el-button
  16. type="primary"
  17. icon="el-icon-plus"
  18. size="mini"
  19. @click="handleAdd"
  20. >新增</el-button>
  21. </el-form-item>
  22. </el-form>
  23. <el-table
  24. v-loading="loading"
  25. :data="categoryList"
  26. border
  27. row-key="id"
  28. :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
  29. >
  30. <el-table-column prop="category_id" label="ID" width="120px" />
  31. <el-table-column prop="category_name" label="分类名称" :show-overflow-tooltip="true" />
  32. <el-table-column label="标签详情">
  33. <template slot-scope="{row}">
  34. <span>{{ row.label_name | getTagDetail }}</span>
  35. </template>
  36. </el-table-column>
  37. <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  38. <template slot-scope="scope">
  39. <el-button
  40. size="mini"
  41. type="text"
  42. icon="el-icon-edit"
  43. @click="handleUpdate(scope.row)"
  44. >修改</el-button>
  45. <el-button
  46. size="mini"
  47. type="text"
  48. icon="el-icon-plus"
  49. @click="handleAdd(scope.row)"
  50. >新增</el-button>
  51. <el-button
  52. size="mini"
  53. type="text"
  54. icon="el-icon-delete"
  55. @click="handleDelete(scope.row)"
  56. >删除</el-button>
  57. </template>
  58. </el-table-column>
  59. </el-table>
  60. <!-- 添加或修改分类对话框 -->
  61. <el-drawer
  62. ref="drawer"
  63. :title="title"
  64. :before-close="cancel"
  65. :visible.sync="open"
  66. direction="rtl"
  67. custom-class="demo-drawer"
  68. size="830px"
  69. >
  70. <div class="demo-drawer__content">
  71. <el-form ref="form" :model="form" :rules="rules" label-position="top" label-width="106px">
  72. <el-row>
  73. <el-col :span="13">
  74. <el-form-item prop="fid">
  75. <span slot="label">
  76. 上级分类
  77. <el-tooltip content="指当前分类停靠的分类归属" placement="top">
  78. <i class="el-icon-question" />
  79. </el-tooltip>
  80. </span>
  81. <treeselect
  82. v-model="form.fid"
  83. :options="categoryOptions"
  84. :normalizer="normalizer"
  85. :show-count="true"
  86. placeholder="选择上级分类"
  87. />
  88. </el-form-item>
  89. </el-col>
  90. <el-col :span="13">
  91. <el-form-item prop="category_name">
  92. <span slot="label">
  93. 分类名称
  94. <el-tooltip content="分类位置显示的说明信息" placement="top">
  95. <i class="el-icon-question" />
  96. </el-tooltip>
  97. </span>
  98. <el-input v-model="form.category_name" placeholder="请输入分类标题" />
  99. </el-form-item>
  100. </el-col>
  101. <template v-for="(item,index) in tagData">
  102. <el-col :span="13" :key="index">
  103. <el-form-item>
  104. <span slot="label">
  105. 标签组名称{{index+1}}
  106. <el-tooltip content="标签组名称" placement="top">
  107. <i class="el-icon-question" />
  108. </el-tooltip>
  109. <el-button v-if="index+1 < tagData.length" class="button-new-tag" size="small" type="warning" @click="removeTag(index)">删除</el-button>
  110. <el-button v-else class="button-new-tag" size="small" @click="addTag">添加</el-button>
  111. </span>
  112. <el-input v-model="item.label" placeholder="请输入标签名称" />
  113. </el-form-item>
  114. <el-form-item style="margin-left:20px">
  115. <span slot="label">
  116. 标签项
  117. <el-tooltip content="标签项名称" placement="top">
  118. <i class="el-icon-question" />
  119. </el-tooltip>
  120. </span>
  121. <el-tag
  122. v-for="(sItem,sIndex) in item.value"
  123. :key="sIndex"
  124. closable
  125. :disable-transitions="false"
  126. @close="handleDelTagItem(sItem,item.value)">
  127. {{sItem}}
  128. </el-tag>
  129. <el-button class="button-new-tag" size="small" @click="openTagDialog(index)">添加标签项</el-button>
  130. </el-form-item>
  131. </el-col>
  132. </template>
  133. </el-row>
  134. </el-form>
  135. <div class="demo-drawer__footer">
  136. <el-button type="primary" @click="submitForm"> </el-button>
  137. <el-button @click="cancel"> </el-button>
  138. </div>
  139. </div>
  140. </el-drawer>
  141. <!-- 标签弹框 -->
  142. <el-dialog class="tagContainer" title="标签名称" :visible.sync="dialogFormVisible">
  143. <el-form>
  144. <el-form-item label="标签名称" :label-width="formLabelWidth">
  145. <el-input v-model="tagName" autocomplete="off"></el-input>
  146. </el-form-item>
  147. </el-form>
  148. <div slot="footer" class="dialog-footer">
  149. <el-button @click="dialogFormVisible = false"> </el-button>
  150. <el-button type="primary" @click="makeSureAddTag"> </el-button>
  151. </div>
  152. </el-dialog>
  153. </el-card>
  154. </template>
  155. <script>
  156. import { listCategory, getCategory, delCategory, addCategory, updateCategory } from '@/api/category'
  157. import Treeselect from '@riophae/vue-treeselect'
  158. import '@riophae/vue-treeselect/dist/vue-treeselect.css'
  159. import IconSelect from '@/components/IconSelect'
  160. export default {
  161. name: 'CategoryManage',
  162. components: { Treeselect, IconSelect },
  163. data() {
  164. return {
  165. // 遮罩层
  166. loading: true,
  167. // 分类表格树数据
  168. categoryList: [],
  169. // 分类树选项
  170. categoryOptions: [],
  171. // 弹出层标题
  172. title: '',
  173. // 是否显示弹出层
  174. open: false,
  175. // 分类状态数据字典
  176. visibleOptions: [],
  177. // 查询参数
  178. queryParams: {
  179. category_name: undefined,
  180. },
  181. // 表单参数
  182. form: {
  183. category_id: undefined,
  184. fid: 0,
  185. category_name: undefined,
  186. },
  187. // 表单校验
  188. rules: {
  189. category_name: [{ required: true, message: '分类标题不能为空', trigger: 'blur' }],
  190. // fid: [{ required: true, message: '请选择父级分类', trigger: 'blur' }]
  191. },
  192. tagData:[],
  193. dialogFormVisible: false,
  194. tagName:'',
  195. handleIndex: null,
  196. formLabelWidth: '120px'
  197. }
  198. },
  199. filters: {
  200. getTagDetail(data) {
  201. if (!data) {
  202. return
  203. }
  204. let str=''
  205. data = JSON.parse(data);
  206. data.forEach(item=>{
  207. if (item.value.length) {
  208. str += `${item.label}${item.value.join("、")}`
  209. }
  210. })
  211. return str
  212. },
  213. },
  214. created() {
  215. this.getList()
  216. },
  217. methods: {
  218. /** 查询分类列表 */
  219. getList() {
  220. this.loading = true
  221. listCategory(this.queryParams).then(response => {
  222. this.categoryList = response.data
  223. this.loading = false
  224. })
  225. },
  226. /** 转换分类数据结构 */
  227. normalizer(node) {
  228. if (node.children && !node.children.length) {
  229. delete node.children
  230. }
  231. return {
  232. id: node.category_id,
  233. label: node.category_name,
  234. children: node.children
  235. }
  236. },
  237. /** 查询分类下拉树结构 */
  238. getTreeselect() {
  239. listCategory().then(response => {
  240. this.categoryOptions = []
  241. const category = { category_id: 0, category_name: '主类目', children: [] }
  242. category.children = response.data
  243. this.categoryOptions.push(category)
  244. })
  245. },
  246. // 取消按钮
  247. cancel() {
  248. this.open = false
  249. this.reset()
  250. },
  251. // 表单重置
  252. reset() {
  253. this.form = {
  254. category_id: undefined,
  255. fid: 0,
  256. category_name: undefined,
  257. }
  258. this.tagData = [
  259. {
  260. label:'',
  261. value:[]
  262. }
  263. ]
  264. // this.resetForm('form')
  265. },
  266. /** 搜索按钮操作 */
  267. handleQuery() {
  268. this.getList()
  269. },
  270. /** 新增按钮操作 */
  271. handleAdd(row) {
  272. this.reset()
  273. this.getTreeselect()
  274. if (row != null) {
  275. this.form.fid = row.category_id
  276. }
  277. console.log(this.form)
  278. this.open = true
  279. this.title = '添加分类'
  280. },
  281. /** 修改按钮操作 */
  282. handleUpdate(row) {
  283. this.reset()
  284. this.getTreeselect()
  285. this.form = {...row}
  286. this.tagData = this.form.label_name ? JSON.parse(this.form.label_name) : [{label:'',value:[]}];
  287. this.open = true
  288. this.title = '修改分类'
  289. },
  290. /** 提交按钮 */
  291. submitForm() {
  292. this.$refs['form'].validate(valid => {
  293. if (valid) {
  294. if( this.tagData.length==1 ){
  295. if (this.validTagData(false)) {
  296. this.form.label_name = JSON.stringify(this.tagData)
  297. } else {
  298. this.form.label_name = null
  299. }
  300. } else {
  301. if (!this.validTagData()) {
  302. return
  303. }
  304. this.form.label_name = JSON.stringify(this.tagData)
  305. }
  306. if (this.form.category_id !== undefined) {
  307. updateCategory(this.form, this.form.category_id).then(response => {
  308. if (response.code === 200) {
  309. this.$message({
  310. message: response.msg,
  311. type: "success",
  312. duration: 2 * 1000,
  313. });
  314. this.open = false
  315. this.getList()
  316. } else {
  317. this.$message({
  318. message: response.msg,
  319. type: "error",
  320. duration: 2 * 1000,
  321. });
  322. }
  323. })
  324. } else {
  325. addCategory(this.form).then(response => {
  326. if (response.code === 200) {
  327. this.$message({
  328. message: response.msg,
  329. type: "success",
  330. duration: 2 * 1000,
  331. });
  332. this.open = false
  333. this.getList()
  334. } else {
  335. this.$message({
  336. message: response.msg,
  337. type: "error",
  338. duration: 2 * 1000,
  339. });
  340. }
  341. })
  342. }
  343. }
  344. })
  345. },
  346. /** 删除按钮操作 */
  347. handleDelete(row) {
  348. console.log(row)
  349. this.$confirm('是否确认删除名称为"' + row.category_name + '"的数据项?', '警告', {
  350. confirmButtonText: '确定',
  351. cancelButtonText: '取消',
  352. type: 'warning'
  353. }).then(function() {
  354. return delCategory({ 'category_id': row.category_id })
  355. }).then((response) => {
  356. if (response.code === 200) {
  357. this.$message({
  358. message: "删除分类成功",
  359. type: "success",
  360. duration: 2 * 1000,
  361. });
  362. this.open = false
  363. this.getList()
  364. } else {
  365. this.$message({
  366. message: "删除分类失败",
  367. type: "error",
  368. duration: 2 * 1000,
  369. });
  370. }
  371. }).catch(function() {})
  372. },
  373. // 删除标签
  374. handleDelTagItem(tag,data) {
  375. data.splice(data.indexOf(tag), 1);
  376. console.log(this.tagData);
  377. },
  378. // 打开标签弹框
  379. openTagDialog(idx) {
  380. this.tagName = ''
  381. this.handleIndex = idx
  382. this.dialogFormVisible = true
  383. },
  384. // 打开标签弹框
  385. makeSureAddTag(){
  386. if (!this.tagName) {
  387. this.$message.warning('请输入标签名称');
  388. return;
  389. }
  390. this.tagData[this.handleIndex]['value'].push(this.tagName)
  391. this.dialogFormVisible = false
  392. },
  393. //添加标签组
  394. addTag(){
  395. if(!this.validTagData()){
  396. return
  397. }
  398. let obj={
  399. label:'',
  400. value:[]
  401. }
  402. this.tagData.push(obj);
  403. },
  404. //移除标签组
  405. removeTag(idx){
  406. this.$confirm('是否确认删除该标签组', '警告', {
  407. confirmButtonText: '确定',
  408. cancelButtonText: '取消',
  409. type: 'warning'
  410. })
  411. .then(() => {
  412. this.tagData.splice(idx, 1);
  413. })
  414. .catch(action => {});
  415. },
  416. // 校验标签数据
  417. validTagData(flag=true){
  418. return this.tagData.every(item=>{
  419. if(!item.label){
  420. flag && this.$message.warning('标签组名称不能为空')
  421. return false
  422. }
  423. if (!item.value.length) {
  424. flag && this.$message.warning('标签项不能为空')
  425. return false
  426. }
  427. return true
  428. })
  429. }
  430. }
  431. }
  432. </script>
  433. <style lang="scss" scoped>
  434. .categoryContainer{
  435. ::v-deep {
  436. .el-col {
  437. padding: 0 5px;
  438. }
  439. .el-drawer__header{
  440. margin-bottom: 0;
  441. }
  442. .el-drawer__body{
  443. padding: 20px;
  444. }
  445. .el-tag + .el-tag {
  446. margin-left: 10px;
  447. }
  448. .button-new-tag {
  449. margin-left: 10px;
  450. height: 32px;
  451. line-height: 30px;
  452. padding-top: 0;
  453. padding-bottom: 0;
  454. }
  455. .input-new-tag {
  456. width: 90px;
  457. margin-left: 10px;
  458. vertical-align: bottom;
  459. }
  460. }
  461. .tagContainer{
  462. ::v-deep .el-input{
  463. width:300px
  464. }
  465. }
  466. }
  467. </style>