userManageList.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. <template>
  2. <a-card :bordered="false" class="userManageList-table-page-search-wrapper">
  3. <div class="userManageList-searchForm">
  4. <a-form-model :model="queryParam" ref="queryForm" layout="inline" v-bind="formItemLayout" @keyup.enter.native="refresh">
  5. <a-row :gutter="20">
  6. <a-col :span="6">
  7. <a-form-model-item label="注册时间" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
  8. <a-range-picker
  9. id="network-time"
  10. v-model="registerTime"
  11. :format="dateFormat"
  12. :placeholder="['开始时间','结束时间']"
  13. :disabledDate="disabledDate"
  14. @change="onChangeregisterTime" />
  15. </a-form-model-item>
  16. </a-col>
  17. <a-col :span="6">
  18. <a-form-model-item label="最后投递时间" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
  19. <a-range-picker
  20. id="network-time"
  21. v-model="lastDeliverTime"
  22. :format="dateFormat"
  23. :placeholder="['开始时间','结束时间']"
  24. :disabledDate="disabledDate"
  25. @change="onChangelastDeliverTime" />
  26. </a-form-model-item>
  27. </a-col>
  28. <a-col :span="6">
  29. <a-form-model-item prop="mobile" label="用户手机" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
  30. <a-input id="userManageList-mobile" allowClear :maxLength="11" v-model="queryParam.mobile" placeholder="请输入用户手机" />
  31. </a-form-model-item>
  32. </a-col>
  33. <a-col :span="6">
  34. <a-form-model-item label="乐豆余额" prop="currentGoldMin" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
  35. <div class="input-number">
  36. <a-input-number id="userManageList-inputNumber" v-model="queryParam.currentGoldMin" :max="999999999" />
  37. <span style="margin:0 11%">-</span>
  38. <a-input-number id="inputNumber" v-model="queryParam.currentGoldMax" :max="999999999" />
  39. </div>
  40. </a-form-model-item>
  41. </a-col>
  42. </a-row>
  43. <a-row :gutter="20">
  44. <a-col :span="6">
  45. <a-form-model-item label="账户状态" prop="state" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
  46. <v-select
  47. v-model="queryParam.state"
  48. id="userManageList-state"
  49. code="ENABLE_FLAG"
  50. placeholder="请选择账户状态"
  51. allowClear></v-select>
  52. </a-form-model-item>
  53. </a-col>
  54. <a-col :span="6">
  55. <a-form-model-item prop="customerRole" label="用户身份" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
  56. <v-select
  57. v-model="queryParam.customerRole"
  58. id="userManageList-customerRole"
  59. code="CUSTOMER_ROLE"
  60. placeholder="请选择用户身份"
  61. allowClear></v-select>
  62. </a-form-model-item>
  63. </a-col>
  64. <a-col :span="6">
  65. <a-form-item label="首次投递网点">
  66. <a-select
  67. id="userManageList-firstDeliveryStationNo"
  68. placeholder="请选择首次投递网点"
  69. allowClear
  70. v-model="queryParam.firstDeliveryStationNo"
  71. :showSearch="true"
  72. option-filter-prop="children"
  73. :filter-option="filterOption"
  74. >
  75. <a-select-option v-for="item in stationData" :key="item.stationNo" :value="item.stationNo">{{ item.name }}</a-select-option>
  76. </a-select>
  77. </a-form-item>
  78. </a-col>
  79. <a-col :span="6">
  80. <a-form-item label="网点标签">
  81. <a-select
  82. style="max-height: 50px;overflow: auto;margin-top: 3px;"
  83. id="userManageList-labelNo"
  84. placeholder="请选择网点标签"
  85. mode="multiple"
  86. allowClear
  87. v-model="queryParam.labelNoList"
  88. :showSearch="true"
  89. option-filter-prop="children"
  90. :filter-option="filterOption"
  91. >
  92. <a-select-option v-for="item in lableData" :key="item.labelNo" :value="item.labelNo">{{ item.labelName }}</a-select-option>
  93. </a-select>
  94. </a-form-item>
  95. </a-col>
  96. </a-row>
  97. <a-row :gutter="20">
  98. <a-col :span="6">
  99. <a-form-model-item label="用户注册方式" prop="introType" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
  100. <v-select
  101. v-model="queryParam.introType"
  102. id="userManageList-introType"
  103. code="INTRO_TYPE"
  104. placeholder="请选择注册方式"
  105. allowClear></v-select>
  106. </a-form-model-item>
  107. </a-col>
  108. <a-col :span="6">
  109. <a-form-model-item label="受邀人" prop="userPhone" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
  110. <a-input v-model.trim="queryParam.userPhone" placeholder="请输入受邀人手机号或姓名" id="userManageList-userPhone" @pressEnter="$refs.table.refresh(true)" allowClear/>
  111. </a-form-model-item>
  112. </a-col>
  113. <a-col style="float: right">
  114. <a-button class="handle-btn serach-btn" id="userManageList-btn-serach" type="primary" @click="refresh">查询</a-button>
  115. <a-button class="handle-btn" type="" id="userManageList-btn-reset" @click="handleReset">重置</a-button>
  116. <a-button
  117. class="export-btn"
  118. id="userManageList-btn-export"
  119. :loading="loading"
  120. @click="handleExport"
  121. v-hasPermission="'B_user_userManage_export'">导出</a-button>
  122. </a-col>
  123. </a-row>
  124. </a-form-model>
  125. </div>
  126. <s-table
  127. ref="table"
  128. size="default"
  129. :rowKey="(record) => record.id"
  130. :columns="columns"
  131. :data="loadData"
  132. :scroll="{ x: 1800}"
  133. bordered>
  134. <!--启用禁用 -->
  135. <template slot="state" slot-scope="text, record">
  136. <a-switch
  137. v-hasPermission="'B_user_userManage_enable'"
  138. checkedChildren="启用"
  139. unCheckedChildren="禁用"
  140. id="userManageList-changeFlagHandle"
  141. :checked="record.state == 1 ? true : false"
  142. @change="changeFlagHandle(text, record)" />
  143. <span v-if="!$hasPermissions('B_user_userManage_enable')">--</span>
  144. </template>
  145. <!-- 受邀人 -->
  146. <template slot="person" slot-scope="text,record">
  147. <p>{{ record.userName }}</p>
  148. <p>{{ record.userPhone }}</p>
  149. <p v-if="!record.userName &&!record.userPhone">--</p>
  150. </template>
  151. <!-- 操作 -->
  152. <template slot="action" slot-scope="text, record">
  153. <a-button id="userManageList-handleUser" type="link" @click="handleUser(record)" v-hasPermission="'B_user_userManage_userDetails'">用户详情</a-button>
  154. <a-button id="userManageList-handleLd" type="link" @click="handleLd(record)" v-hasPermission="'B_user_userManage_LdDetails'">乐豆明细</a-button>
  155. <span v-if="!$hasPermissions('B_user_userManage_userDetails') && (!$hasPermissions('B_user_userManage_LdDetails'))">--</span>
  156. </template>
  157. </s-table>
  158. </a-card>
  159. </template>
  160. <script>
  161. import {
  162. STable,
  163. VSelect
  164. } from '@/components'
  165. import {
  166. customerList,
  167. changeStatus,
  168. customeExport
  169. } from '@/api/userInfo.js'
  170. import { lableSeleteList, stationSeleteList } from '@/api/labelSetting.js'
  171. import moment from 'moment'
  172. export default {
  173. name: 'UserManageList',
  174. components: {
  175. STable,
  176. VSelect
  177. },
  178. data () {
  179. return {
  180. formItemLayout: {
  181. labelCol: {
  182. span: 7
  183. },
  184. wrapperCol: {
  185. span: 17
  186. }
  187. },
  188. registerTime: [], // 注册时间
  189. lastDeliverTime: [], // 最后投递时间
  190. lableData: [], // 网点标签
  191. stationData: [], // 首次投递
  192. dateFormat: 'YYYY-MM-DD',
  193. // 查询参数
  194. queryParam: {
  195. mobile: '', // 用户手机
  196. state: '', // 账户状态
  197. customerRole: '', // 用户身份
  198. currentGoldMin: '', // 乐豆余额最小值
  199. currentGoldMax: '', // 乐豆余额最大值
  200. beginDate: null, // 最后投递时间的开始时间
  201. endDate: null, // 最后投递时间的结束时间
  202. beginRegisterTime: null, // 注册时间最小值
  203. endRegisterTime: null, // 注册时间最大值
  204. labelNoList: [], // 网点标签
  205. firstDeliveryStationNo: undefined, // 首次投递
  206. introType: '', // 注册方式
  207. userPhone: '' // 受邀人
  208. },
  209. loading: false, // 导出loading
  210. // 表头
  211. columns: [{ title: '序号', dataIndex: 'no', width: 80, align: 'center', fixed: 'left' },
  212. { title: '用户手机', dataIndex: 'mobile', width: 150, align: 'center' },
  213. { title: '用户注册方式', dataIndex: 'introTypeDictValue', width: 150, align: 'center', customRender: (text) => { return text || '--' } },
  214. { title: '受邀人', dataIndex: 'person', width: 150, align: 'center', scopedSlots: { customRender: 'person' } },
  215. { title: '用户身份', dataIndex: 'customerRoleDictValue', width: 100, align: 'center' },
  216. { title: '乐豆余额', dataIndex: 'currentGold', width: 100, align: 'center', customRender: (text) => { return text || 0 } },
  217. { title: '累计乐豆', dataIndex: 'totalGold', width: 100, align: 'center', customRender: (text) => { return text || 0 } },
  218. { title: '注册时间', dataIndex: 'registerTime', width: 150, align: 'center', customRender: (text) => { return text || '--' } },
  219. { title: '最后登录时间', dataIndex: 'lastLoginTime', width: 150, align: 'center', customRender: (text) => { return text || '--' } },
  220. { title: '最后投递时间', dataIndex: 'lastDeliveryTime', width: 150, align: 'center', customRender: (text) => { return text || '--' } },
  221. { title: '状态', width: 100, dataIndex: 'state', align: 'center', scopedSlots: { customRender: 'state' } },
  222. { title: '首次投递网点', dataIndex: 'firstDeliveryStationName', width: 150, align: 'center', customRender: (text) => { return text || '--' } },
  223. { title: '网点标签', dataIndex: 'labelName', width: 150, align: 'center', customRender: (text) => { return text || '--' } },
  224. { title: '操作', scopedSlots: { customRender: 'action' }, width: 120, align: 'center' }],
  225. // 加载数据方法 必须为 Promise 对象
  226. loadData: parameter => {
  227. const searchData = Object.assign(parameter, this.queryParam)
  228. if (this.registerTime && this.registerTime.length) {
  229. searchData.beginRegisterTime = moment(this.registerTime[0]).format('YYYY-MM-DD 00:00:00')
  230. searchData.endRegisterTime = moment(this.registerTime[1]).format('YYYY-MM-DD 23:59:59')
  231. } else {
  232. searchData.beginRegisterTime = null
  233. searchData.endRegisterTime = null
  234. }
  235. if (this.lastDeliverTime && this.lastDeliverTime.length) {
  236. searchData.beginDate = moment(this.lastDeliverTime[0]).format('YYYY-MM-DD 00:00:00')
  237. searchData.endDate = moment(this.lastDeliverTime[1]).format('YYYY-MM-DD 23:59:59')
  238. } else {
  239. searchData.beginDate = null
  240. searchData.endDate = null
  241. }
  242. return customerList(searchData).then(res => {
  243. if (res.status == 200) {
  244. const no = (res.data.pageNo - 1) * res.data.pageSize
  245. for (let i = 0; i < res.data.list.length; i++) {
  246. const _item = res.data.list[i]
  247. _item.no = no + i + 1
  248. _item.status = _item.status + '' === '1'
  249. }
  250. return res.data
  251. }
  252. })
  253. }
  254. }
  255. },
  256. mounted () {
  257. this.getlableSeleteList()
  258. this.getStationSeleteList()
  259. },
  260. beforeRouteEnter (to, from, next) {
  261. next(vm => {
  262. vm.$refs.queryForm.resetFields()
  263. vm.registerTime = []
  264. vm.lastDeliverTime = []
  265. })
  266. },
  267. methods: {
  268. // 不可选日期
  269. disabledDate (date, dateStrings) {
  270. return date && date.valueOf() > Date.now()
  271. },
  272. // 注册时间change
  273. onChangeregisterTime (dates, dateStrings) {
  274. if ((dates, dateStrings)) {
  275. this.queryParam.beginRegisterTime = dateStrings[0]
  276. this.queryParam.endRegisterTime = dateStrings[1]
  277. }
  278. },
  279. // 最后投递时间change
  280. onChangelastDeliverTime (dates, dateStrings) {
  281. if ((dates, dateStrings)) {
  282. this.queryParam.beginDate = dateStrings[0]
  283. this.queryParam.endDate = dateStrings[1]
  284. }
  285. },
  286. filterOption (input, option) {
  287. return (
  288. option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
  289. )
  290. },
  291. // 获取标签数据
  292. getlableSeleteList () {
  293. lableSeleteList().then(res => {
  294. if (res.status == 200) {
  295. this.lableData = res.data || []
  296. }
  297. })
  298. },
  299. // 获取首次投递数据
  300. getStationSeleteList () {
  301. stationSeleteList().then(res => {
  302. if (res.status == 200) {
  303. this.stationData = res.data || []
  304. }
  305. })
  306. },
  307. // 重置
  308. refresh () {
  309. const isONull = this.queryParam.currentGoldMin === null || this.queryParam.currentGoldMin === undefined
  310. const isOEmpty = this.queryParam.currentGoldMin === ''
  311. const isOZero = this.queryParam.currentGoldMin === 0
  312. const isTNull = this.queryParam.currentGoldMax === null || this.queryParam.currentGoldMax === undefined
  313. const isTEmpty = this.queryParam.currentGoldMax === ''
  314. const isTZero = this.queryParam.currentGoldMax === 0
  315. // 第一个为空(可为null可为空字符)第二个不为空
  316. // 第一个不为空第二个为空(可为null可为空字符)
  317. // 第一个大于第二个
  318. if ((isONull || isOEmpty) && (this.queryParam.currentGoldMax || isTZero)) {
  319. this.$message.error('请输入正确的查询范围!')
  320. return
  321. }
  322. if ((this.queryParam.currentGoldMin || isOZero) && (isTNull || isTEmpty)) {
  323. this.$message.error('请输入正确的查询范围!')
  324. return
  325. }
  326. if (this.queryParam.currentGoldMin > this.queryParam.currentGoldMax) {
  327. this.$message.error('请输入正确的查询范围!')
  328. return
  329. }
  330. this.queryParam.currentGoldMin = this.queryParam.currentGoldMin > 999999999 ? 999999999 : this.queryParam.currentGoldMin
  331. this.queryParam.currentGoldMax = this.queryParam.currentGoldMax > 999999999 ? 999999999 : this.queryParam.currentGoldMax
  332. this.$refs.table.refresh(true)
  333. },
  334. // 查看用户详情
  335. handleUser (row) {
  336. this.$router.push({
  337. path: `/userInfo/userManageList_user/detail/${row.id}`
  338. })
  339. },
  340. // 查看乐豆详情
  341. handleLd (row) {
  342. this.$router.push({
  343. path: '/userInfo/userManageList_Ld/detail',
  344. query: {
  345. customerNo: row.customerNo,
  346. id: row.id
  347. }
  348. })
  349. },
  350. // 更改启用禁用状态
  351. changeFlagHandle (text, record) {
  352. const _this = this
  353. const _data = {
  354. id: record.id,
  355. state: record.state == 1 ? '0' : '1'
  356. }
  357. changeStatus(_data).then(res => {
  358. if (res.status == 200) {
  359. _this.$message.success(res.message)
  360. _this.$refs.table.refresh()
  361. } else {
  362. record.state = !record.state
  363. }
  364. })
  365. },
  366. // 重置
  367. handleReset () {
  368. this.$refs.queryForm.resetFields()
  369. this.queryParam.beginDate = null // 最后投递时间的开始时间
  370. this.queryParam.endDate = null // 最后投递时间的结束时间
  371. this.queryParam.beginRegisterTime = null // 注册时间最小值
  372. this.queryParam.endRegisterTime = null // 注册时间最大值
  373. this.registerTime = []
  374. this.lastDeliverTime = []
  375. this.queryParam.labelNoList = []
  376. this.queryParam.firstDeliveryStationNo = undefined
  377. this.$refs.table.refresh(true)
  378. },
  379. // 导出
  380. handleExport () {
  381. const params = this.queryParam
  382. if (this.registerTime && this.registerTime.length) {
  383. params.beginRegisterTime = moment(this.registerTime[0]).format('YYYY-MM-DD 00:00:00')
  384. params.endRegisterTime = moment(this.registerTime[1]).format('YYYY-MM-DD 23:59:59')
  385. } else {
  386. params.beginRegisterTime = null
  387. params.endRegisterTime = null
  388. }
  389. if (this.lastDeliverTime && this.lastDeliverTime.length) {
  390. params.beginDate = moment(this.lastDeliverTime[0]).format('YYYY-MM-DD 00:00:00')
  391. params.endDate = moment(this.lastDeliverTime[1]).format('YYYY-MM-DD 23:59:59')
  392. } else {
  393. params.beginDate = null
  394. params.endDate = null
  395. }
  396. // if (this.lastDeliverTime && this.lastDeliverTime.length) {
  397. // params.beginDate = moment(this.lastDeliverTime[0])
  398. // params.endDate = moment(this.lastDeliverTime[1])
  399. // if (!params.beginDate && !params.endDate) {
  400. // this.$message.error('请先选择需要导出的最后投递时间区间再进行导出!')
  401. // return
  402. // }
  403. // // 判断两个时间段是否相差m个月 第二个参数指相差单位,第三个参数指是否返回浮点形式(小数)
  404. // if (moment(params.endDate).diff(moment(params.beginDate), 'months', true) > 3) {
  405. // this.$message.error('单次最多只能导出3个月的数据,请缩小最后投递时间查询区间后再进行导出!')
  406. // return
  407. // }
  408. // } else {
  409. // params.beginDate = ''
  410. // params.endDate = ''
  411. // }
  412. // if (this.registerTime && this.registerTime.length) {
  413. // params.beginRegisterTime = moment(this.registerTime[0])
  414. // params.endRegisterTime = moment(this.registerTime[1])
  415. // if (!params.beginRegisterTime && !params.endRegisterTime) {
  416. // this.$message.error('请先选择需要导出的注册时间区间再进行导出!')
  417. // return
  418. // }
  419. // // 判断两个时间段是否相差m个月 第二个参数指相差单位,第三个参数指是否返回浮点形式(小数)
  420. // if (moment(params.endRegisterTime).diff(moment(params.beginRegisterTime), 'months', true) > 3) {
  421. // this.$message.error('单次最多只能导出3个月的数据,请缩小注册时间查询区间后再进行导出!')
  422. // return
  423. // }
  424. // } else {
  425. // params.beginRegisterTime = ''
  426. // params.endRegisterTime = ''
  427. // }
  428. // if (this.lastDeliverTime.length == 0 && this.registerTime.length == 0) {
  429. // this.$message.error('请先选择需要导出的注册时间区间或最后投递时间区间再进行导出(3个月以内)!')
  430. // return
  431. // }
  432. this.$confirm({
  433. title: '提示',
  434. content: '导出过程可能需要一段时间,且导出期间不可进行其他操作,确认要导出吗?',
  435. onOk: () => {
  436. this.loading = true
  437. customeExport(params).then(res => {
  438. this.loading = false
  439. this.download(res)
  440. })
  441. },
  442. onCancel () {
  443. }
  444. })
  445. },
  446. download (data) {
  447. if (!data) {
  448. return
  449. }
  450. const url = window.URL.createObjectURL(new Blob([data]))
  451. const link = document.createElement('a')
  452. link.style.display = 'none'
  453. link.href = url
  454. // const a = moment().format('YYYYMMDDhhmmss')
  455. const fname = '用户列表'
  456. link.setAttribute('download', fname + '.xlsx')
  457. document.body.appendChild(link)
  458. link.click()
  459. }
  460. }
  461. }
  462. </script>
  463. <style lang="less" scoped>
  464. .userManageList-table-page-search-wrapper {
  465. .userManageList-searchForm {
  466. .ant-form-inline .ant-form-item {
  467. width: 100%;
  468. }
  469. // 搜索框的下间距
  470. .ant-form-item {
  471. margin-bottom: 10px;
  472. }
  473. .input-number {
  474. display: flex;
  475. margin-top: 3px;
  476. }
  477. .handle-btn {
  478. margin-top: 4px;
  479. }
  480. .serach-btn {
  481. margin-right: 10px;
  482. }
  483. }
  484. .export-btn {
  485. background-color: #ff9900;
  486. border-color: #ff9900;
  487. color: #fff;
  488. margin-left: 10px;
  489. }
  490. .export-btn.ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger),
  491. .export-btn.ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger) {
  492. color: #fff;
  493. border-color: #ff9900;
  494. }
  495. }
  496. </style>