index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. <template>
  2. <div>
  3. <ag-grid-layout
  4. toolbar
  5. :table-height="tableHeight"
  6. theme="ag-theme-alpine"
  7. :column-defs="columnDefs"
  8. :row-data="rowData"
  9. :locale-text="localeText"
  10. :grid-options="gridOptions"
  11. :default-col-def="defaultColDef"
  12. :animate-rows="true"
  13. :row-selection="rowSelection"
  14. :enable-cell-change-flash="true"
  15. @filterChanged="filterModifed"
  16. @sortChanged="gridSortChange"
  17. >
  18. <!-- @rowDoubleClicked="getList"-->
  19. <div slot="toolbar" class="inner-toolbar">
  20. <div class="toolbar-search">
  21. <en-table-search :placeholder="this.$t('action.keywords')" @search="handlerSearch"/>
  22. </div>
  23. <div class="toolbar-btns">
  24. <el-button type="primary" size="mini" @click="createMessageType">{{
  25. this.$t('mc.messageTemplateModule.addMessageTemplate')
  26. }}
  27. </el-button>
  28. </div>
  29. </div>
  30. <el-pagination
  31. v-if="pageData"
  32. slot="pagination"
  33. :current-page="pageData.page_no"
  34. :page-sizes="[10, 20, 50, 100]"
  35. :page-size="pageData.page_size"
  36. layout="total, sizes, prev, pager, next, jumper"
  37. :total="pageData.data_total"
  38. @size-change="handlePageSizeChange"
  39. @current-change="handlePageCurrentChange"
  40. />
  41. </ag-grid-layout>
  42. <el-dialog :title.sync="formtitle" :visible.sync="formshow" width="35%">
  43. <div style="position: relative;" @click="closeMenu">
  44. <el-form ref="editform" :rules="rules" label-width="120px" :model="formmodel">
  45. <el-row>
  46. <el-col :span="24">
  47. <el-form-item :label="this.$t('mc.messageTemplateModule.templateTitle')" prop="template_title">
  48. <el-input
  49. v-model="formmodel.template_title"
  50. clearable
  51. :maxlength="100"
  52. :placeholder="this.$t('mc.messageTemplateModule.templateTitle')"
  53. />
  54. </el-form-item>
  55. <el-form-item :label="this.$t('mc.messageTemplateModule.templateContent')" prop="template_content">
  56. <el-input
  57. v-model="formmodel.template_content"
  58. clearable
  59. ref="template_content"
  60. type="textarea"
  61. @focus="closeMenu"
  62. @blur="recordCursorPosition"
  63. @contextmenu.prevent.native="openMenu($event)"
  64. :placeholder="this.$t('mc.messageTemplateModule.templateContent')"
  65. />
  66. <span>{{this.$t('mc.messageTemplateModule.insertParamerTip')}}</span>
  67. </el-form-item>
  68. <el-form-item label="" prop="bool_shared">
  69. <el-checkbox v-model="formmodel.bool_shared" :true-label="1" :false-label="0">
  70. {{ this.$t('mc.messageTemplateModule.boolShared') }}
  71. </el-checkbox>
  72. </el-form-item>
  73. </el-col>
  74. </el-row>
  75. </el-form>
  76. </div>
  77. <div slot="footer" class="dialog-footer">
  78. <el-button @click="formshow = false">{{ this.$t('action.cancel') }}</el-button>
  79. <el-button type="primary" :disabled="this.formmodel.part_id!==Number(this.$store.getters.partId)" @click="handlerFormSubmit('editform')">{{ this.$t('action.yes') }}</el-button>
  80. </div>
  81. <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
  82. <li @click="insertAtCursor(item)" v-for="item in templateParamers" :key="item.id">{{ item.param_name }}</li>
  83. </ul>
  84. </el-dialog>
  85. </div>
  86. </template>
  87. <script>
  88. import ButtonCellRenderList from "@/components/AgGridCellRender/ButtonCellRenderList.vue";
  89. import ButtonCellRender from "@/components/AgGridCellRender/ButtonCellRender.vue";
  90. import ListFilter from "@/components/AgGridCustomFilter/ListFilter.vue";
  91. import RadioFilter from "@/components/AgGridCustomFilter/RadioFilter.vue";
  92. import {AG_GRID_LOCALE_CN} from "@/utils/AgGridVueLocaleCn";
  93. import * as API_MessageTemplate from "@/api/message_template";
  94. import {unix2Date} from "@/utils/Foundation";
  95. import * as API_TemplateParamer from "@/api/template_paramer";
  96. export default {
  97. name: "index",
  98. components: {ButtonCellRenderList, ButtonCellRender, ListFilter, RadioFilter},
  99. data() {
  100. return {
  101. tableData: [],
  102. /** 列表参数 */
  103. params: {
  104. page_size: 20,
  105. page_no: 1,
  106. fixedCondition: ' part_id = ' + this.$store.getters.partId+' or bool_shared = 1',
  107. },
  108. /** 新建组织弹出参数 **/
  109. formtitle: this.$t('mc.messageTemplateModule.addMessageTemplate'),
  110. formshow: false,
  111. /** 频道订阅设置 */
  112. formSubscribe: false,
  113. formmodel: {
  114. part_id:this.$store.getters.partId
  115. },
  116. frameGroups: [],
  117. rules: {
  118. template_title: [
  119. {required: true, message: this.$t('mc.messageTemplateModule.templateTitleRequired'), trigger: 'blur'}
  120. ],
  121. template_content: [
  122. {required: true, message: this.$t('mc.messageTemplateModule.templateContentRequired'), trigger: 'blur'},
  123. {validator: this.validateContent, trigger: 'blur'}
  124. ]
  125. },
  126. /** ag-grid参数 **/
  127. pageData: [],
  128. loading: false,
  129. columnDefs: null,
  130. rowData: null,
  131. defaultColDef: null,
  132. gridOptions: null,
  133. gridApi: null,
  134. columnApi: null,
  135. localeText: AG_GRID_LOCALE_CN,
  136. filterState: null,
  137. rowSelection: null,
  138. frameworkComponents: null,
  139. visible:false,
  140. left:0,
  141. top:0,
  142. selectionStart:0,
  143. selectionEnd:0,
  144. templateParamers: [],
  145. boolTransfer: [
  146. {key: this.$t('mc.templateParamerModule.yes'), value: 1},
  147. {key: this.$t('mc.templateParamerModule.no'), value: 0}
  148. ],
  149. /** 频道订阅者情况数组 */
  150. channelSubscribers: [],
  151. subscribeTitle: '',
  152. choiceAll: this.$t('action.choiceAll')
  153. }
  154. },
  155. computed: {
  156. tableHeight() {
  157. return this.mainAreaHeight - 130
  158. }
  159. },
  160. beforeMount() {
  161. this.gridOptions = {}
  162. this.columnDefs = [
  163. {
  164. headerName: '#',
  165. headerCheckboxSelection: true,
  166. headerCheckboxSelectionFilteredOnly: true,
  167. checkboxSelection: true,
  168. sortable: false, filter: false,
  169. width: 100,
  170. resizable: false,
  171. valueGetter: this.hashValueGetter
  172. },
  173. {headerName: 'ID', field: 'id', sortable: true, filter: 'agNumberColumnFilter', width: 130},
  174. {
  175. headerName: this.$t('mc.messageTemplateModule.templateTitle'),
  176. field: 'template_title',
  177. filter: 'agNumberColumnFilter',
  178. sortable: true,
  179. flex: 1
  180. },
  181. {
  182. headerName: this.$t('mc.messageTemplateModule.templateContent'),
  183. field: 'template_content',
  184. sortable: true,
  185. filter: 'agTextColumnFilter',
  186. flex: 1
  187. },
  188. {
  189. headerName: this.$t('mc.messageTemplateModule.boolShared'),
  190. field: 'bool_shared',
  191. sortable: true,
  192. filterFramework: 'RadioFilter',
  193. filterParams: {
  194. listData: this.boolTransfer
  195. },
  196. width: 150,
  197. cellRenderer: this.booleanFormatter
  198. },
  199. {
  200. headerName: this.$t('boardTitle.partId'), field: 'part_id', sortable: true, filter: 'agNumberColumnFilter', flex: 1
  201. },
  202. // lockPosition 锁定位置,会在第一列
  203. // lockPinned = true 不能拖动然后固定
  204. // resizeable 单元个大小是否可以调整
  205. {
  206. headerName: this.$t('action.handle'), field: 'id',
  207. cellRendererFramework: 'ButtonCellRenderList',
  208. cellRendererParams: param => {
  209. // console.log(param,Number(this.$store.getters.partId))
  210. return {
  211. list: [
  212. {
  213. onClick: this.handleEdit,
  214. label: this.$t('action.edit'),
  215. buttonType: 'primary',
  216. buttonSize: 'mini'
  217. },
  218. {
  219. onClick: this.deleteSingle,
  220. label: this.$t('action.delete'),
  221. buttonType: 'danger',
  222. buttonSize: 'mini',
  223. disabled: param.data.part_id!==Number(this.$store.getters.partId)
  224. }
  225. ]
  226. }
  227. },
  228. filter: false,
  229. pinned: 'right',
  230. lockPinned: true,
  231. minWidth: this.$i18n.locale === 'zh' ? 310 : 350,
  232. resizable: false,
  233. sortable: false
  234. }
  235. ]
  236. this.defaultColDef = {
  237. sortable: true,
  238. resizable: true,
  239. comparator: this.dateCustomComparator,
  240. filterParams: {
  241. debounceMs: 200,
  242. newRowsAction: 'keep',
  243. textCustomComparator: this.textCustomComparator,
  244. comparator: this.dateCustomComparator
  245. }
  246. }
  247. this.rowSelection = 'multiple'
  248. },
  249. async mounted() {
  250. window.onresize = this.windowResize
  251. this.templateParamers= await API_TemplateParamer.getAll()
  252. this.gridApi = this.gridOptions.api
  253. this.gridColumnApi = this.gridOptions.columnApi
  254. // 设置默认排序字段,应用列状态之后会触发 gridSortChange 函数,会调用getlist,后面不需要再调用this.getlist
  255. this.gridColumnApi.applyColumnState({
  256. state: [
  257. {
  258. colId: 'id',
  259. sort: 'asc'
  260. }
  261. ]
  262. })
  263. },
  264. methods: {
  265. windowResize() {
  266. this.$set(this, 'mainAreaHeight', Number(document.documentElement.clientHeight) - 84)
  267. },
  268. openMenu(e) {
  269. // console.log(e)
  270. const menuMinWidth = 105
  271. const offsetLeft = e.target.offsetWidth // container margin left
  272. const offsetWidth = this.$el.offsetWidth // container width
  273. const maxLeft = offsetWidth - menuMinWidth // left boundary
  274. const left = e.x // 15: margin right
  275. this.left=left
  276. // if (left > maxLeft) {
  277. // this.left = maxLeft
  278. // } else {
  279. // this.left = left
  280. // }
  281. this.top = e.y+10
  282. this.visible = true
  283. },
  284. recordCursorPosition(e) {
  285. this.selectionStart = e.srcElement.selectionStart
  286. this.selectionEnd = e.srcElement.selectionEnd
  287. },
  288. insertAtCursor(item) {
  289. var val = this.formmodel.template_content;
  290. var start = this.selectionStart;
  291. var end = this.selectionEnd;
  292. // console.log('start',start,end)
  293. const text='${'+item.param_name+'}'
  294. this.formmodel.template_content = val.substring(0, start) + text + val.substring(end);
  295. this.$refs.template_content.selectionStart = this.$refs.template_content.selectionEnd = start + text.length;
  296. this.closeMenu()
  297. },
  298. closeMenu() {
  299. this.visible = false
  300. },
  301. handlerDelete(ids) {
  302. this.$confirm(this.$t('action.sureDelete'), this.$t('action.waring'), {
  303. confirmButtonText: this.$t('action.yes'),
  304. cancelButtonText: this.$t('action.cancel'),
  305. type: 'warning'
  306. }).then(() => {
  307. API_MessageTemplate.remove(ids).then(
  308. response => {
  309. this.getList()
  310. this.$message({
  311. type: 'success',
  312. message: this.$t('action.deleted')
  313. })
  314. }
  315. ).catch(response => {
  316. this.$message({
  317. type: 'info',
  318. message: response.message
  319. })
  320. })
  321. }).catch(() => {
  322. this.$message({
  323. type: 'info',
  324. message: this.$t('action.cancelDelete')
  325. })
  326. })
  327. },
  328. booleanFormatter(params) {
  329. if (params.value === null || params.value === undefined) return ''
  330. else{
  331. return params.value ? `<span style="color:green;">${this.$t('mc.templateParamerModule.yes')}</span>` :`<span style="color:red;">${this.$t('mc.templateParamerModule.no')}</span>`
  332. }
  333. },
  334. deleteSingle(row) {
  335. this.handlerDelete(row.id)
  336. },
  337. extractParams(template) {
  338. const pattern = /\$\{([^}]+)\}/g;
  339. let match;
  340. const params = [];
  341. while ((match = pattern.exec(template))) {
  342. params.push(match[1]); // 添加到params数组中
  343. }
  344. return params;
  345. },
  346. /**
  347. * 创建 消息类型
  348. */
  349. createMessageType() {
  350. this.formshow = true
  351. this.formmodel = {
  352. part_id:Number(this.$store.getters.partId),
  353. bool_shared:false
  354. }
  355. console.log(this.formmodel)
  356. this.formtitle=this.$t('mc.messageTemplateModule.addMessageTemplate')
  357. },
  358. /** 分页大小发生改变 */
  359. handlePageSizeChange(size) {
  360. this.params.page_size = size
  361. this.getList()
  362. },
  363. /** 分页页数发生改变 */
  364. handlePageCurrentChange(page) {
  365. this.params.page_no = page
  366. this.getList()
  367. },
  368. /** 加载列表数据 */
  369. getList() {
  370. this.loading = true
  371. const param = this.MixinClone(this.params)
  372. this.gridApi.showLoadingOverlay()
  373. API_MessageTemplate.getList(param).then(response => {
  374. this.loading = false
  375. // this.tableData = [...response.data]
  376. this.pageData = {
  377. page_no: response.page_no,
  378. page_size: response.page_size,
  379. data_total: response.data_total
  380. }
  381. this.$nextTick(() => {
  382. const node = this.gridApi.getDisplayedRowAtIndex(0)
  383. if (node !== null && node !== undefined) {
  384. node.setSelected(true)
  385. }
  386. })
  387. this.rowData = [...response.data]
  388. this.refreshPlayStatus()
  389. }).catch(() => {
  390. this.loading = false
  391. })
  392. },
  393. /** 处理搜索 */
  394. handlerSearch(keywords) {
  395. this.params.query = keywords
  396. this.getList()
  397. },
  398. /** 处理字段排序 */
  399. tableSort(column) {
  400. if (column.order !== null) {
  401. this.params.sort = column.prop
  402. this.params.dir = column.order === 'ascending' ? 'asc' : 'desc'
  403. } else {
  404. this.params.sort = null
  405. this.params.dir = null
  406. }
  407. this.getList()
  408. },
  409. /**
  410. * 格式化unix时间戳
  411. **/
  412. unixDateFormatter(param) {
  413. if (!param.value) return ''
  414. return unix2Date(param.value * 1000)
  415. },
  416. gridSortChange(param) {
  417. const columnState = param.columnApi.getColumnState()
  418. // 排序状态
  419. const sortState = columnState.filter(function (s) {
  420. return s.sort != null
  421. }).map(function (s) {
  422. return {
  423. colId: s.colId,
  424. sort: s.sort,
  425. sortIndex: s.sortIndex
  426. }
  427. }).sort(function (a, b) {
  428. return a.sortIndex - b.sortIndex
  429. })
  430. if (sortState.length > 0) {
  431. if (sortState.length === 1) {
  432. this.params.sort = sortState[0].colId
  433. this.params.dir = sortState[0].sort
  434. } else {
  435. let sortstring = ''
  436. sortState.forEach(function (item) {
  437. sortstring += item.colId + ' ' + item.sort + ','
  438. })
  439. this.params.sort = sortstring.substring(0, sortstring.length - 1)
  440. this.params.dir = ' '
  441. }
  442. } else {
  443. delete this.params.sort
  444. delete this.params.dir
  445. }
  446. this.getList()
  447. },
  448. filterModifed(param) { // todo 通过转换后的数值过滤,需要转回原始数值
  449. var model = param.api.getFilterModel()
  450. this.params.filter = JSON.stringify(model)
  451. this.getList()
  452. },
  453. handleEdit(row) {
  454. this.formtitle = this.$t('mc.messageTemplateModule.editMessageTemplate')
  455. this.formmodel = {
  456. ...row
  457. }
  458. this.formshow = true
  459. },
  460. validateContent(rule, value, callback) {
  461. // 自定义校验规则
  462. const paramers = this.extractParams(value)
  463. const _this=this
  464. if(paramers.length>0){
  465. paramers.forEach(item=>{
  466. if(!this.templateParamers.find(i=>i.param_name===item)){
  467. callback(new Error(_this.$t('mc.messageTemplateModule.templateContentError',[item])))
  468. }
  469. })
  470. callback()
  471. }else{
  472. callback()
  473. }
  474. },
  475. /**
  476. * 提交新增表单
  477. * @param formname
  478. */
  479. handlerFormSubmit(formName) {
  480. this.$refs[formName].validate((valid) => {
  481. if (valid) {
  482. if (!this.formmodel.id) {
  483. /** 新增 */
  484. this.formmodel.part_id = this.$store.getters.partId
  485. API_MessageTemplate.add(this.formmodel).then(() => {
  486. this.formshow = false
  487. this.$message.success(this.$t('action.addSuccess'))
  488. this.getList()
  489. })
  490. } else {
  491. API_MessageTemplate.update(this.formmodel.id, this.formmodel).then(() => {
  492. this.formshow = false
  493. this.$message.success(this.$t('action.editSuccess'))
  494. this.getList()
  495. })
  496. }
  497. } else {
  498. this.$message.error(this.$t('action.fromError'))
  499. }
  500. })
  501. },
  502. }
  503. }
  504. </script>
  505. <style scoped>
  506. .el-dropdown-link {
  507. cursor: pointer;
  508. color: #409EFF;
  509. }
  510. .el-icon-arrow-down {
  511. font-size: 12px;
  512. }
  513. .contextmenu {
  514. margin: 0;
  515. background: #fff;
  516. z-index: 3000;
  517. position: fixed;
  518. list-style-type: none;
  519. padding: 5px 0;
  520. border-radius: 4px;
  521. font-size: 12px;
  522. font-weight: 400;
  523. color: #333;
  524. box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
  525. li {
  526. margin: 0;
  527. padding: 7px 16px;
  528. cursor: pointer;
  529. &:hover {
  530. background: #eee;
  531. }
  532. }
  533. }
  534. </style>