list.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. <template>
  2. <a-card size="small" :bordered="false" class="productInfoList-wrap">
  3. <a-spin :spinning="spinning" tip="Loading...">
  4. <!-- 搜索条件 -->
  5. <div class="table-page-search-wrapper">
  6. <a-form layout="inline" @keyup.enter.native="$refs.table.refresh(true)">
  7. <a-row :gutter="15">
  8. <a-col :md="6" :sm="24">
  9. <a-form-item label="产品名称">
  10. <a-input id="productInfoList-name" v-model.trim="queryParam.name" allowClear placeholder="请输入产品名称"/>
  11. </a-form-item>
  12. </a-col>
  13. <a-col :md="6" :sm="24">
  14. <a-form-item label="产品编码/原厂编码">
  15. <a-input id="productInfoList-queryWord" v-model.trim="queryParam.queryWord" allowClear placeholder="请输入产品编码/原厂编码"/>
  16. </a-form-item>
  17. </a-col>
  18. <a-col :md="6" :sm="24">
  19. <a-form-item label="品牌">
  20. <a-select
  21. placeholder="请选择"
  22. id="productInfoList-productBrandSn"
  23. allowClear
  24. v-model="queryParam.productBrandSn"
  25. :showSearch="true"
  26. option-filter-prop="children"
  27. :filter-option="filterOption">
  28. <a-select-option v-for="item in productBrandList" :key="item.brandSn" :value="item.brandSn">{{ item.brandName }}</a-select-option>
  29. </a-select>
  30. </a-form-item>
  31. </a-col>
  32. <template v-if="advanced">
  33. <a-col :md="6" :sm="24">
  34. <a-form-item label="产品分类">
  35. <a-cascader
  36. @change="changeProductType"
  37. expand-trigger="hover"
  38. change-on-select
  39. :options="productTypeList"
  40. :fieldNames="{ label: 'productTypeName', value: 'productTypeSn', children: 'children' }"
  41. id="productInfoList-productType"
  42. placeholder="请选择产品分类"
  43. allowClear
  44. v-model="productType" />
  45. </a-form-item>
  46. </a-col>
  47. <a-col :md="6" :sm="24">
  48. <a-form-item label="产品状态">
  49. <v-select code="PRODUCT_STATUS" id="productInfoList-state" v-model="queryParam.state" allowClear placeholder="请选择产品状态"></v-select>
  50. </a-form-item>
  51. </a-col>
  52. <a-col :md="6" :sm="24">
  53. <a-form-item label="定价状态">
  54. <v-select code="PRICING_STATUS" id="productInfoList-pricingState" v-model="queryParam.pricingState" allowClear placeholder="请选择定价状态"></v-select>
  55. </a-form-item>
  56. </a-col>
  57. </template>
  58. <a-col :md="6" :sm="24">
  59. <a-button style="margin-bottom: 18px;" type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="productInfoList-refresh">查询</a-button>
  60. <a-button style="margin: 0 0 18px 5px" @click="resetSearchForm" :disabled="disabled" id="productInfoList-reset">重置</a-button>
  61. <a-button
  62. v-if="$hasPermissions('B_productInfo_export')"
  63. style="margin-left: 5px"
  64. type="primary"
  65. class="button-warning"
  66. @click="handleExport"
  67. :disabled="disabled"
  68. :loading="exportLoading"
  69. id="productInfoList-export">导出</a-button>
  70. <a @click="advanced=!advanced" style="margin-left: 8px">
  71. {{ advanced ? '收起' : '展开' }}
  72. <a-icon :type="advanced ? 'up' : 'down'"/>
  73. </a>
  74. </a-col>
  75. </a-row>
  76. </a-form>
  77. </div>
  78. <!-- 操作按钮 -->
  79. <div class="table-operator">
  80. <a-button id="productInfoList-add" type="primary" v-if="$hasPermissions('B_productInfo_add')" class="button-error" @click="handleEdit()">新增</a-button>
  81. <a-button
  82. id="productInfoList-batchAudit"
  83. type="primary"
  84. v-if="$hasPermissions('B_productInfo_batchAudit')"
  85. class="button-warning"
  86. :loading="loadingAudit"
  87. @click="handleBatchAudit"
  88. style="margin: 0 15px;">批量审核</a-button>
  89. <a-button
  90. id="productInfoList-batchLaunch"
  91. type="primary"
  92. v-if="$hasPermissions('B_productInfo_batchLaunch')"
  93. class="button-primary"
  94. :loading="loadingLaunch"
  95. @click="handleBatchLaunch"
  96. style="margin: 0 15px;">批量上线</a-button>
  97. <a-button
  98. id="productInfoList-batchDownline"
  99. type="primary"
  100. v-if="$hasPermissions('B_productInfo_batchDownline')"
  101. class="button-grey"
  102. :loading="loadingDownline"
  103. @click="handleBatchDownline"
  104. style="margin: 0 15px;">批量下线</a-button>
  105. <span style="margin-left: 8px" v-if="$hasPermissions('B_productInfo_batchAudit') || $hasPermissions('B_productInfo_batchLaunch') || $hasPermissions('B_productInfo_batchDownline')">
  106. <template v-if="hasSelected">{{ `已选 ${selectedRowKeys.length} 项` }}</template>
  107. </span>
  108. </div>
  109. <s-table
  110. class="sTable"
  111. ref="table"
  112. size="default"
  113. :row-selection=" showSelect ?{ selectedRowKeys: selectedRowKeys, onChange: onChange, onSelect: onSelectChange, onSelectAll: onSelectAllChange }:null"
  114. :rowKey="(record) => record.id"
  115. :columns="columns"
  116. :data="loadData"
  117. :scroll="{ x: 2150, y: tableHeight }"
  118. bordered>
  119. <!-- 自定义表头 -->
  120. <template slot="arrowFalgTitle">
  121. <a-tooltip placement="top">
  122. <template slot="title">
  123. <span>自有即箭冠产品,非自有即非箭冠产品</span>
  124. </template>
  125. 自有<a-icon type="question-circle" :style="{ marginLeft: '10px' }" />
  126. </a-tooltip>
  127. </template>
  128. <template slot="arrowFalg" slot-scope="text, record">
  129. <span v-if="record.arrowFalg">{{ record.arrowFalg == 1 ? '是' : '否' }}</span>
  130. <span v-else>--</span>
  131. </template>
  132. <!-- 产品分类 -->
  133. <template slot="productType" slot-scope="text, record">
  134. <span v-if="record.productTypeName2 || record.productTypeName3">{{ record.productTypeName2 }} {{ record.productTypeName3 ? '>' : '' }} {{ record.productTypeName3 }}</span>
  135. <span v-else>--</span>
  136. </template>
  137. <!-- 定价状态 -->
  138. <template slot="pricingState" slot-scope="text, record">
  139. <a-badge :color="record.pricingState=='WAIT_PRICING'?'gold':record.pricingState=='WAIT_PRICING_AUDIT'?'volcano':'#87d068'" :text="record.pricingStateDictValue" />
  140. </template>
  141. <!-- 操作 -->
  142. <template slot="action" slot-scope="text, record">
  143. <a-button
  144. size="small"
  145. type="link"
  146. v-if="record.state=='WAIT' && $hasPermissions('B_productInfo_audit')"
  147. class="button-warning"
  148. @click="handleAudit(record)"
  149. id="productInfoList-audit-btn">审核</a-button>
  150. <a-button
  151. size="small"
  152. type="link"
  153. v-if="(record.state=='WAIT_ONLINE'||record.state=='OFFLINE') && $hasPermissions('B_productInfo_launch')"
  154. class="button-primary"
  155. @click="handleLaunch(record)"
  156. id="productInfoList-launch-btn">上线</a-button>
  157. <a-button
  158. size="small"
  159. type="link"
  160. v-if="record.state=='ONLINE' && $hasPermissions('B_productInfo_downline')"
  161. class="button-grey"
  162. @click="handleDownline(record)"
  163. id="productInfoList-downline-btn">下线</a-button>
  164. <a-button
  165. size="small"
  166. type="link"
  167. v-if="$hasPermissions('B_productInfo_edit')"
  168. class="button-info"
  169. @click="handleEdit(record)"
  170. id="productInfoList-edit-btn">编辑</a-button>
  171. <a-button
  172. size="small"
  173. type="link"
  174. v-if="$hasPermissions('B_productInfo_detail')"
  175. class="button-success"
  176. @click="handleDetail(record)"
  177. id="productInfoList-detail-btn">详情</a-button>
  178. <a-button
  179. size="small"
  180. type="link"
  181. v-if="record.state=='WAIT' && $hasPermissions('B_productInfo_del')"
  182. class="button-error"
  183. @click="handleDel(record)"
  184. id="productInfoList-del-btn">删除</a-button>
  185. <span v-if="!(record.state=='WAIT' && $hasPermissions('B_productInfo_audit')) && !((record.state=='WAIT_ONLINE'||record.state=='OFFLINE') && $hasPermissions('B_productInfo_launch')) && !(record.state=='ONLINE' && $hasPermissions('B_productInfo_downline')) && !$hasPermissions('B_productInfo_edit') && !$hasPermissions('B_productInfo_detail') && !(record.state=='WAIT' && $hasPermissions('B_productInfo_del'))">--</span>
  186. </template>
  187. </s-table>
  188. </a-spin>
  189. <!-- 产品详情 -->
  190. <product-info-detail-modal :openModal="openModal" :itemSn="itemSn" @close="closeModal" />
  191. <!-- 产品下线 -->
  192. <product-info-offline-modal :openModal="openOfflineModal" :offlineProductList="offlineProductList" @close="closeOfflineModal" @ok="$refs.table.refresh()" />
  193. </a-card>
  194. </template>
  195. <script>
  196. import moment from 'moment'
  197. import { STable, VSelect } from '@/components'
  198. import productInfoDetailModal from './detailModal.vue'
  199. import productInfoOfflineModal from './offlineModal.vue'
  200. import { productBrandQuery } from '@/api/productBrand'
  201. import { productTypeQuery } from '@/api/productType'
  202. import { productList, productAudit, productBatchAudit, productDel, productOnline, productBatchOnline, productExport } from '@/api/product'
  203. export default {
  204. components: { STable, VSelect, productInfoDetailModal, productInfoOfflineModal },
  205. data () {
  206. return {
  207. spinning: false,
  208. advanced: false, // 高级搜索 展开/关闭
  209. queryParam: { // 查询条件
  210. name: '', // 产品名称
  211. queryWord: '', // 产品编码/原厂编码
  212. productBrandSn: undefined, // 产品品牌
  213. productTypeSn1: '', // 产品一级分类
  214. productTypeSn2: '', // 产品二级分类
  215. productTypeSn3: '', // 产品三级分类
  216. state: undefined, // 产品状态
  217. pricingState: undefined // 定价状态
  218. },
  219. productType: [],
  220. disabled: false, // 查询、重置按钮是否可操作
  221. exportLoading: false,
  222. columns: [
  223. { title: '序号', dataIndex: 'no', width: 80, align: 'center' },
  224. { title: '创建时间', dataIndex: 'createDate', width: 160, align: 'center', customRender: function (text) { return text || '--' } },
  225. { title: '产品名称', dataIndex: 'name', align: 'center', ellipsis: true, customRender: function (text) { return text || '--' } },
  226. { title: '产品编码', dataIndex: 'code', width: 220, align: 'center', customRender: function (text) { return text || '--' } },
  227. { title: '原厂编码', dataIndex: 'origCode', width: 220, align: 'center', customRender: function (text) { return text || '--' } },
  228. { title: '品牌', dataIndex: 'productBrandName', width: 200, align: 'center', customRender: function (text) { return text || '--' } },
  229. { title: '产品分类', scopedSlots: { customRender: 'productType' }, width: 200, align: 'center' },
  230. { slots: { title: 'arrowFalgTitle' }, scopedSlots: { customRender: 'arrowFalg' }, width: 100, align: 'center' },
  231. { title: '最近修改时间', dataIndex: 'updateDate', width: 160, align: 'center', customRender: function (text) { return text || '--' } },
  232. { title: '产品状态', dataIndex: 'stateDictValue', width: 140, align: 'center', customRender: function (text) { return text || '--' } },
  233. { title: '定价状态', scopedSlots: { customRender: 'pricingState' }, width: 140, align: 'center' },
  234. { title: '操作', scopedSlots: { customRender: 'action' }, width: 250, align: 'center', fixed: 'right' }
  235. ],
  236. selectedRowKeys: [], // Check here to configure the default column
  237. selectedRows: [],
  238. loadingAudit: false,
  239. loadingLaunch: false,
  240. loadingDownline: false,
  241. // 加载数据方法 必须为 Promise 对象
  242. loadData: parameter => {
  243. this.disabled = true
  244. return productList(Object.assign(parameter, this.queryParam)).then(res => {
  245. const data = res.data
  246. const no = (data.pageNo - 1) * data.pageSize
  247. for (var i = 0; i < data.list.length; i++) {
  248. data.list[i].no = no + i + 1
  249. }
  250. this.disabled = false
  251. return data
  252. })
  253. },
  254. openModal: false, // 查看详情 弹框
  255. itemSn: '', // 当前sn
  256. openOfflineModal: false, // 下线 弹框
  257. offlineProductList: [], // 下线 当前所选数据
  258. productBrandList: [], // 品牌下拉数据
  259. productTypeList: [] // 分类下拉数据
  260. }
  261. },
  262. computed: {
  263. tableHeight () {
  264. return window.innerHeight - (this.advanced ? 425 : 370)
  265. },
  266. hasSelected () {
  267. return this.selectedRowKeys.length > 0
  268. },
  269. // 是否显示table选择框
  270. showSelect () {
  271. return this.$hasPermissions('B_productInfo_batchAudit') || this.$hasPermissions('B_productInfo_batchLaunch') || this.$hasPermissions('B_productInfo_batchDownline')
  272. }
  273. },
  274. methods: {
  275. onChange (selectedRowKeys, selectedRows) {
  276. this.selectedRowKeys = selectedRowKeys
  277. },
  278. onSelectChange (record, selected, selectedRows, nativeEvent) {
  279. const _this = this
  280. if (selected) { // 选择
  281. this.selectedRows.push(record)
  282. } else { // 取消
  283. this.selectedRows.map((item, index) => {
  284. if (item.id == record.id) {
  285. _this.selectedRows.splice(index, 1)
  286. }
  287. })
  288. }
  289. },
  290. // 本页全选/取消全选
  291. onSelectAllChange (selected, selectedRows, changeRows) {
  292. const _this = this
  293. if (selected) { // 选择
  294. this.selectedRows = [...this.selectedRows, ...changeRows]
  295. } else { // 取消
  296. this.selectedRows.map((item, index) => {
  297. this.selectedRows.map((subItem, ind) => {
  298. if (item.id == subItem.id) {
  299. _this.selectedRows.splice(index, 1)
  300. }
  301. })
  302. })
  303. }
  304. },
  305. // 审核
  306. handleAudit (row) {
  307. const _this = this
  308. this.$confirm({
  309. title: '提示',
  310. content: '确认要审核吗?',
  311. centered: true,
  312. onOk () {
  313. _this.spinning = true
  314. productAudit({ sn: row.productSn }).then(res => {
  315. if (res.status == 200) {
  316. _this.$message.success(res.message)
  317. _this.$refs.table.refresh()
  318. _this.spinning = false
  319. } else {
  320. _this.spinning = false
  321. }
  322. })
  323. }
  324. })
  325. },
  326. // 批量审核
  327. handleBatchAudit () {
  328. const _this = this
  329. if (_this.selectedRowKeys.length < 1) {
  330. _this.$message.warning('请在列表勾选后再进行批量操作!')
  331. return
  332. }
  333. let num = 0
  334. const obj = []
  335. _this.selectedRows.map(item => {
  336. if (item.state == 'WAIT') {
  337. num++
  338. obj.push(item.productSn)
  339. }
  340. })
  341. if (num < 1) {
  342. _this.$message.warning('当前数据不可操作!')
  343. return
  344. }
  345. this.$confirm({
  346. title: '提示',
  347. content: '已选有效数据' + num + '条,确认要批量审核吗?',
  348. centered: true,
  349. onOk () {
  350. _this.loadingAudit = true
  351. _this.spinning = true
  352. productBatchAudit(obj).then(res => {
  353. _this.loadingAudit = false
  354. if (res.status == 200) {
  355. _this.selectedRowKeys = []
  356. _this.selectedRows = []
  357. _this.$message.success(res.message)
  358. _this.$refs.table.refresh()
  359. _this.spinning = false
  360. } else {
  361. _this.spinning = false
  362. }
  363. })
  364. }
  365. })
  366. },
  367. // 批量上线
  368. handleBatchLaunch () {
  369. const _this = this
  370. if (_this.selectedRowKeys.length < 1) {
  371. _this.$message.warning('请在列表勾选后再进行批量操作!')
  372. return
  373. }
  374. let num = 0
  375. const obj = []
  376. _this.selectedRows.map(item => {
  377. if (item.state == 'WAIT_ONLINE' || item.state == 'OFFLINE') {
  378. num++
  379. obj.push(item.productSn)
  380. }
  381. })
  382. if (num < 1) {
  383. _this.$message.warning('当前数据不可操作!')
  384. return
  385. }
  386. this.$confirm({
  387. title: '提示',
  388. content: '已选有效数据' + num + '条,确认要批量上线吗?',
  389. centered: true,
  390. onOk () {
  391. _this.loadingLaunch = true
  392. _this.spinning = true
  393. productBatchOnline(obj).then(res => {
  394. _this.loadingLaunch = false
  395. if (res.status == 200) {
  396. _this.selectedRowKeys = []
  397. _this.selectedRows = []
  398. _this.$message.success(res.message)
  399. _this.$refs.table.refresh()
  400. _this.spinning = false
  401. } else {
  402. _this.spinning = false
  403. }
  404. })
  405. }
  406. })
  407. },
  408. // 批量下线
  409. handleBatchDownline () {
  410. const _this = this
  411. if (_this.selectedRowKeys.length < 1) {
  412. _this.$message.warning('请在列表勾选后再进行批量操作!')
  413. return
  414. }
  415. let num = 0
  416. _this.offlineProductList = []
  417. _this.selectedRows.map(item => {
  418. if (item.state == 'ONLINE') {
  419. num++
  420. _this.offlineProductList.push({ productSn: item.productSn, code: item.code, commonProductList: [] })
  421. }
  422. })
  423. if (num < 1) {
  424. _this.$message.warning('当前数据不可操作!')
  425. return
  426. }
  427. this.openOfflineModal = true
  428. },
  429. // 重置
  430. resetSearchForm () {
  431. this.queryParam.name = ''
  432. this.queryParam.queryWord = ''
  433. this.queryParam.productBrandSn = undefined
  434. this.queryParam.productTypeSn1 = ''
  435. this.queryParam.productTypeSn2 = ''
  436. this.queryParam.productTypeSn3 = ''
  437. this.queryParam.state = undefined
  438. this.queryParam.pricingState = undefined
  439. this.productType = []
  440. this.$refs.table.refresh(true)
  441. },
  442. // 新增/编辑
  443. handleEdit (row) {
  444. if (row) { // 编辑
  445. this.$router.push({ path: `/productManagement/productInfo/edit/${row.id}/${row.productSn}` })
  446. } else { // 新增
  447. this.$router.push({ path: '/productManagement/productInfo/add' })
  448. }
  449. },
  450. // 上线
  451. handleLaunch (row) {
  452. const _this = this
  453. this.$confirm({
  454. title: '提示',
  455. content: '确认要上线吗?',
  456. centered: true,
  457. onOk () {
  458. _this.spinning = true
  459. productOnline({ sn: row.productSn }).then(res => {
  460. if (res.status == 200) {
  461. _this.$message.success(res.message)
  462. _this.$refs.table.refresh()
  463. _this.spinning = false
  464. } else {
  465. _this.spinning = false
  466. }
  467. })
  468. }
  469. })
  470. },
  471. // 下线
  472. handleDownline (row) {
  473. this.offlineProductList.push({ productSn: row.productSn, code: row.code, commonProductList: [] })
  474. this.openOfflineModal = true
  475. },
  476. // 删除
  477. handleDel (row) {
  478. const _this = this
  479. this.$confirm({
  480. title: '提示',
  481. content: '确认要删除吗?',
  482. centered: true,
  483. onOk () {
  484. _this.spinning = true
  485. productDel({ sn: row.productSn }).then(res => {
  486. if (res.status == 200) {
  487. _this.$message.success(res.message)
  488. _this.$refs.table.refresh()
  489. _this.spinning = false
  490. } else {
  491. _this.spinning = false
  492. }
  493. })
  494. }
  495. })
  496. },
  497. filterOption (input, option) {
  498. return (
  499. option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
  500. )
  501. },
  502. // 详情
  503. handleDetail (row) {
  504. this.itemSn = row.productSn
  505. this.openModal = true
  506. },
  507. // 关闭弹框
  508. closeModal () {
  509. this.itemSn = ''
  510. this.openModal = false
  511. },
  512. // 关闭下线弹框
  513. closeOfflineModal () {
  514. this.selectedRowKeys = []
  515. this.selectedRows = []
  516. this.offlineProductList = []
  517. this.openOfflineModal = false
  518. },
  519. // 导出
  520. handleExport () {
  521. const _this = this
  522. const params = this.queryParam
  523. this.exportLoading = true
  524. _this.spinning = true
  525. productExport(params).then(res => {
  526. this.exportLoading = false
  527. _this.spinning = false
  528. if (res.type == 'application/json') {
  529. var reader = new FileReader()
  530. reader.addEventListener('loadend', function () {
  531. const obj = JSON.parse(reader.result)
  532. _this.$notification.error({
  533. message: '提示',
  534. description: obj.message
  535. })
  536. })
  537. reader.readAsText(res)
  538. } else {
  539. this.download(res)
  540. }
  541. })
  542. },
  543. download (data) {
  544. if (!data) { return }
  545. const url = window.URL.createObjectURL(new Blob([data]))
  546. const link = document.createElement('a')
  547. link.style.display = 'none'
  548. link.href = url
  549. const a = moment().format('YYYYMMDDHHmmss')
  550. const fname = '产品列表' + a
  551. link.setAttribute('download', fname + '.xlsx')
  552. document.body.appendChild(link)
  553. link.click()
  554. },
  555. // 产品分类 change
  556. changeProductType (val, opt) {
  557. this.queryParam.productTypeSn1 = val[0] ? val[0] : ''
  558. this.queryParam.productTypeSn2 = val[1] ? val[1] : ''
  559. this.queryParam.productTypeSn3 = val[2] ? val[2] : ''
  560. },
  561. // 产品品牌 列表
  562. getProductBrand () {
  563. productBrandQuery({}).then(res => {
  564. if (res.status == 200) {
  565. this.productBrandList = res.data
  566. } else {
  567. this.productBrandList = []
  568. }
  569. })
  570. },
  571. // 产品分类 列表
  572. getProductType () {
  573. productTypeQuery({}).then(res => {
  574. if (res.status == 200) {
  575. this.productTypeList = res.data
  576. } else {
  577. this.productTypeList = []
  578. }
  579. })
  580. }
  581. },
  582. beforeRouteEnter (to, from, next) {
  583. next(vm => {
  584. vm.getProductBrand()
  585. vm.getProductType()
  586. })
  587. }
  588. }
  589. </script>