List.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. <template>
  2. <div class="classify">
  3. <div class="classify-list">
  4. <div class="classify-content">
  5. <div class="list" v-for="(v, i) in datas.keyList" :key="'0' + i">
  6. <div class="list-box">
  7. <div class="list-value">
  8. <p>关键词: {{v.key.join(' ') || '--'}}</p>
  9. <p>附加词: {{v.appendkey.join('、') || '--'}}</p>
  10. <p>排除词: {{v.notkey.join('、') || '--'}}</p>
  11. </div>
  12. <div class="list-icon" @click="deleteKeyFn(i)"></div>
  13. <div class="list-edit" @click="editKeyFn(v, i)">
  14. 编辑
  15. <i class="tri-down"></i>
  16. </div>
  17. </div>
  18. </div>
  19. <div class="words-add" @click="addKeyFn()">
  20. <i class="el-icon-plus"></i>
  21. </div>
  22. </div>
  23. </div>
  24. <!-- 关键词dialog -->
  25. <el-dialog
  26. custom-class="sub-dialog"
  27. :visible.sync="dialog.editKey"
  28. :close-on-click-modal="false"
  29. :show-close="false"
  30. center
  31. width="800px"
  32. v-if="dialog.editKey"
  33. >
  34. <KeyCard @onCancel="dialog.editKey = false" @onConfirm="submitKeywords">
  35. <div slot="header">修改关键词</div>
  36. <div class="key-edit-content">
  37. <ScopeEdit ref="keyEditRef" :datas="props"></ScopeEdit>
  38. </div>
  39. </KeyCard>
  40. </el-dialog>
  41. </div>
  42. </template>
  43. <script>
  44. import { Tooltip, Dialog, Input, Button } from 'element-ui'
  45. import KeyCard from '@/components/selector/SelectorCard'
  46. import ScopeEdit from './Edit'
  47. export default {
  48. name: 'scope-list',
  49. components: {
  50. [Tooltip.name]: Tooltip,
  51. [Dialog.name]: Dialog,
  52. [Input.name]: Input,
  53. [Button.name]: Button,
  54. KeyCard,
  55. ScopeEdit
  56. },
  57. props: {
  58. datas: {
  59. keyList: Array,
  60. maxCount: Number
  61. }
  62. },
  63. data () {
  64. return {
  65. dialog: {
  66. editKey: false // 修改关键词弹框
  67. },
  68. // 传给dialog子组件的数据
  69. props: {
  70. ways: '', // 编辑还是新增
  71. keyIndex: null, // 关键词下标
  72. key: [], // 关键词
  73. notkey: [], // 排除词
  74. appendkey: [] // 附加词
  75. }
  76. }
  77. },
  78. computed: {},
  79. mounted () {},
  80. methods: {
  81. // 添加关键词
  82. addKeyFn () {
  83. const isCan = this.getIsAdd()
  84. if (isCan) {
  85. return this.$message({
  86. type: 'warning',
  87. message: '关键词超出最大限制'
  88. })
  89. }
  90. this.dialog.editKey = true
  91. this.props.ways = 'add'
  92. this.props.key = []
  93. this.props.notkey = []
  94. this.props.appendkey = []
  95. },
  96. // 删除单个关键词
  97. deleteKeyFn (i) {
  98. const data = this.datas.keyList
  99. if (!data) return
  100. data.splice(i, 1)
  101. this.$emit('updateKey', data)
  102. },
  103. // 编辑单个关键词
  104. editKeyFn (v, i) {
  105. this.props.ways = 'edit'
  106. this.dialog.editKey = true
  107. // 把当前关键词传到dialog key,notkey,appendKey都为数组
  108. this.props.key = v.key
  109. this.props.notkey = v.notkey
  110. this.props.appendkey = v.appendkey
  111. this.props.keyIndex = i
  112. },
  113. // 清空传值
  114. clearPropsData () {
  115. this.props.key = []
  116. this.props.notkey = []
  117. this.props.appendkey = []
  118. },
  119. // 修改关键词dialog 保存数据
  120. submitKeywords () {
  121. const data = this.datas.keyList
  122. const refs = this.$refs.keyEditRef.cur
  123. const keyArr = this.getKeyTotalArray()
  124. const type = this.props.ways
  125. const obj = {
  126. key: refs.key.split(' '),
  127. notkey: refs.notkey,
  128. appendkey: refs.appendkey
  129. }
  130. if (refs.key === '') {
  131. return this.$message({
  132. type: 'warning',
  133. message: '关键词不能为空'
  134. })
  135. }
  136. // 判断附加词是否重复
  137. if (this.getArrIsRepeat(refs.appendkey)) {
  138. return this.$message({
  139. type: 'warning',
  140. message: '设置的附加词重复,请调整后再添加'
  141. })
  142. }
  143. // 判断排除词是否重复
  144. if (this.getArrIsRepeat(refs.notkey)) {
  145. return this.$message({
  146. type: 'warning',
  147. message: '设置的排除词重复,请调整后再添加'
  148. })
  149. }
  150. if (type === 'add') {
  151. if (keyArr.indexOf(refs.key) > -1) {
  152. return this.$message({
  153. type: 'warning',
  154. message: '关键词不能重复'
  155. })
  156. }
  157. data.push(obj)
  158. } else if (type === 'edit') {
  159. // 如果当前编辑的关键词和修改框里的关键词不相同 需校验是否重复
  160. if (data[this.props.keyIndex].key.toString() !== refs.key) {
  161. if (keyArr.indexOf(refs.key) > -1) {
  162. return this.$message({
  163. type: 'warning',
  164. message: '关键词不能重复'
  165. })
  166. }
  167. }
  168. data[this.props.keyIndex].key = refs.key.split(' ')
  169. data[this.props.keyIndex].notkey = refs.notkey
  170. data[this.props.keyIndex].appendkey = refs.appendkey
  171. }
  172. // 通知父组件发请求修改并更新
  173. this.$emit('updateKey', data)
  174. this.dialog.editKey = false
  175. },
  176. // 获取所有关键词的key的属性,并返回一个数组(主要用于判断添加关键词是否重复)
  177. getKeyTotalArray () {
  178. const data = this.datas.keyList
  179. const keysArr = []
  180. data.forEach((s) => {
  181. if (s && s.key && Array.isArray(s.key)) {
  182. s.key.forEach((v) => {
  183. keysArr.push(v)
  184. })
  185. }
  186. })
  187. console.log(keysArr, 'keysArr')
  188. return keysArr
  189. },
  190. // 判断附加词、排除词是否重复
  191. getArrIsRepeat (arr) {
  192. this.removeEmptyInput(arr)
  193. return (new Set(arr)).size !== arr.length
  194. },
  195. // 判断是否超限
  196. getIsAdd () {
  197. const keyArr = this.getKeyTotalArray()
  198. if (keyArr.length >= this.datas.maxCount) {
  199. return true
  200. } else {
  201. return false
  202. }
  203. },
  204. // 输入框为空移除
  205. removeEmptyInput (arr) {
  206. for (let i = 0; i < arr.length; i++) {
  207. // eslint-disable-next-line
  208. if (arr[i] === '' || arr[i] === null || typeof (arr[i]) === undefined) {
  209. arr.splice(i, 1)
  210. i = i - 1
  211. }
  212. }
  213. return arr
  214. }
  215. }
  216. }
  217. </script>
  218. <style lang="scss" scoped>
  219. // dialog 自定义class样式
  220. .sub-dialog{
  221. border-radius: 8px;
  222. .selector-card{
  223. width: 800px;
  224. height: auto;
  225. }
  226. .key-edit-content,.class-edit-content{
  227. width: 740px;
  228. padding: 30px 0;
  229. height: auto;
  230. max-height: 340px;
  231. margin: 0 auto;
  232. border: 1px solid #ececec;
  233. overflow-y: scroll;
  234. box-sizing: border-box;
  235. }
  236. .item{
  237. display: flex;
  238. align-items: center;
  239. justify-content: center;
  240. margin-bottom: 10px;
  241. }
  242. .item-label{
  243. margin-right: 8px;
  244. min-width: 120px;
  245. height: 40px;
  246. color: #1d1d1d;
  247. font-size: 14px;
  248. line-height: 40px;
  249. text-align: right;
  250. }
  251. .item-label-required:before{
  252. content: "*";
  253. color: #f56c6c;
  254. margin-right: 2px;
  255. }
  256. .item-value{
  257. width: 352px;
  258. }
  259. .custom-long-input{
  260. width: 352px;
  261. }
  262. .custom-short-input{
  263. width: 170px;
  264. }
  265. .delete-class{
  266. display: flex;
  267. flex-direction: column;
  268. align-items: center;
  269. padding: 32px 32px 42px;
  270. background: #FFFFFF;
  271. border-radius: 6px;
  272. .delete-class-header{
  273. font-size: 18px;
  274. line-height: 28px;
  275. color: #1D1D1D;
  276. }
  277. .delete-class-content{
  278. padding: 20px 0 42px;
  279. color: #686868;
  280. font-size: 14px;
  281. line-height: 22px;
  282. }
  283. .delete-class-footer{
  284. display: flex;
  285. align-items: center;
  286. .confirm,
  287. .cancel {
  288. padding: 10px 50px;
  289. margin: 0 20px;
  290. }
  291. ::v-deep {
  292. .el-button--primary {
  293. color: #2cb7ca;
  294. background: none;
  295. border-color: #2cb7ca;
  296. &:hover {
  297. color: #fff;
  298. background-color: #2cb7ca;
  299. }
  300. }
  301. .el-button--default {
  302. &:hover,
  303. &:active {
  304. color: #2cb7ca;
  305. border-color: #2cb7ca;
  306. background: #eaf8fa;
  307. }
  308. }
  309. }
  310. }
  311. }
  312. }
  313. .classify-list{
  314. margin-bottom: 30px;
  315. .icon-edit,.icon-delete{
  316. display: inline-block;
  317. width: 16px;
  318. height: 16px;
  319. background-repeat: no-repeat;
  320. background-position: center center;
  321. cursor: pointer;
  322. }
  323. .icon-edit{
  324. margin: 0 10px;
  325. background-image: url('~@/assets/images/icon-edit.png');
  326. background-size: contain;
  327. }
  328. .icon-delete{
  329. background-image: url('~@/assets/images/icon-delete.png');
  330. background-size: contain;
  331. }
  332. .classify-content{
  333. display: flex;
  334. align-items: center;
  335. justify-content: flex-start;
  336. flex-wrap: wrap;
  337. .list{
  338. padding-top: 10px;
  339. margin-right: 10px;
  340. margin-bottom: 10px;
  341. width: 160px;
  342. height: 80px;
  343. box-sizing: border-box;
  344. &:hover .list-edit{
  345. transform: scaleY(1);
  346. transition: transform .1s;
  347. }
  348. &:hover .list-box{
  349. border: 1px solid #2cb7ca;
  350. box-sizing: border-box;
  351. }
  352. }
  353. .list:nth-child(6n) {
  354. margin-right: 0;
  355. }
  356. .list-box{
  357. position: relative;
  358. display: flex;
  359. padding: 10px 10px 10px 16px;
  360. border: 1px solid #ececec;
  361. border-radius: 9px;
  362. box-sizing: border-box;
  363. cursor: pointer;
  364. }
  365. .list-edit{
  366. transform: scaleY(0);
  367. transition: transform .1s;
  368. position: absolute;
  369. top: -40px;
  370. left: 50%;
  371. margin-left: -22px;
  372. padding: 10px;
  373. color: #fff;
  374. background: #1d1d1d;
  375. border-radius: 4px;
  376. font-size: 12px;
  377. cursor: pointer;
  378. .tri-down{
  379. position: absolute;
  380. bottom: -6px;
  381. left: 50%;
  382. margin-left: -5px;
  383. width: 0;
  384. height: 0;
  385. border-left: 6px solid transparent;
  386. border-right: 6px solid transparent;
  387. border-top: 6px solid #1d1d1d;
  388. }
  389. }
  390. .list-value{
  391. width: 124px;
  392. font-size: 12px;
  393. line-height: 20px;
  394. color: #000;
  395. text-overflow: ellipsis;
  396. overflow: hidden;
  397. white-space: nowrap;
  398. p{
  399. @extend .list-value
  400. }
  401. }
  402. .list-icon{
  403. @extend .icon-delete;
  404. width: 12px;
  405. height: 12px;
  406. }
  407. .words-add{
  408. width: 162px;
  409. height: 80px;
  410. display: flex;
  411. align-items: center;
  412. justify-content: center;
  413. font-size: 24px;
  414. border: 1px solid #ececec;
  415. margin: 10px 0 0 0;
  416. border-radius: 9px;
  417. color: #c4c4c4;
  418. cursor: pointer;
  419. }
  420. }
  421. }
  422. </style>