shopOperation.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. <template>
  2. <div class="m-container">
  3. <h2>
  4. <el-page-header @back="onCancel"
  5. :content="(pageTitle[pageType]) + '商品'"></el-page-header>
  6. </h2>
  7. <div class="m-core">
  8. <el-form :model="form"
  9. :rules="rules"
  10. ref="form"
  11. label-width="120px">
  12. <el-form-item label="货号"
  13. prop="sn">
  14. <el-input v-model.trim="form.sn"
  15. :disabled="pageDisabled"
  16. placeholder="请输入货号"
  17. style="width: 400px"></el-input>
  18. </el-form-item>
  19. <el-form-item label="品牌"
  20. prop="brand">
  21. <el-input v-model.trim="form.brand"
  22. :disabled="pageDisabled"
  23. placeholder="请输入品牌"
  24. style="width: 400px"></el-input>
  25. </el-form-item>
  26. <!-- <el-form-item label="备查货号" prop="supplyChannel" v-if="pageType == 'create'">
  27. <el-input v-model.trim="form.supplyChannel" placeholder="请输入备查货号" style="width: 400px"></el-input>
  28. </el-form-item> -->
  29. <el-form-item label="商品名称"
  30. prop="name">
  31. <el-input v-model.trim="form.name"
  32. placeholder="请输入商品名称"
  33. :disabled="pageDisabled"
  34. style="width: 400px"></el-input>
  35. </el-form-item>
  36. <el-form-item label="商品类型"
  37. prop="type">
  38. <el-select v-model.trim="form.type"
  39. placeholder="请选择商品类型"
  40. :disabled="pageDisabled"
  41. style="width: 400px !important;">
  42. <el-option v-for="(item, index) in goodsType"
  43. :key="index"
  44. :label="item.label"
  45. :value="item.value"></el-option>
  46. </el-select>
  47. </el-form-item>
  48. <el-form-item label="商品分类"
  49. prop="goodsCategoryId">
  50. <el-select v-model.trim="form.goodsCategoryId"
  51. placeholder="请选择商品分类"
  52. :disabled="pageDisabled"
  53. style="width: 400px !important;"
  54. filterable>
  55. <el-option v-for="item in categoryList"
  56. :key="item.value"
  57. :label="item.label"
  58. :value="item.value">
  59. </el-option>
  60. </el-select>
  61. </el-form-item>
  62. <el-form-item label="商品型号"
  63. prop="specification">
  64. <el-input v-model.trim="form.specification"
  65. placeholder="请输入商品型号"
  66. :disabled="pageDisabled"
  67. style="width: 400px"></el-input>
  68. </el-form-item>
  69. <!-- <el-form-item label="内部库存" prop="stockCount">
  70. <el-input type="number" :disabled="pageType != 'create'" v-model.trim="form.stockCount" placeholder="请输入内部库存" style="width: 400px"></el-input>
  71. </el-form-item>
  72. <el-form-item label="税务库存" prop="taxStockCount">
  73. <el-input type="number" :disabled="pageType != 'create'" v-model.trim="form.taxStockCount" placeholder="请输入税务库存" style="width: 400px"></el-input>
  74. </el-form-item> -->
  75. <el-form-item label="库存类型"
  76. prop="stockType">
  77. <el-select v-model="form.stockType"
  78. placeholder="请选择库存类型"
  79. :disabled="pageDisabled"
  80. style="width: 400px !important;">
  81. <el-option v-for="(item, index) in stockType"
  82. :key="index"
  83. :label="item.label"
  84. :value="item.value"></el-option>
  85. </el-select>
  86. </el-form-item>
  87. <el-form-item label="市场价"
  88. prop="marketPrice">
  89. <el-input type="number"
  90. placeholder="请输入市场价"
  91. :disabled="pageDisabled"
  92. @mousewheel.native.prevent
  93. v-model.trim="form.marketPrice"
  94. style="width: 400px"></el-input>
  95. </el-form-item>
  96. <el-form-item label="零售价"
  97. prop="discountPrice">
  98. <el-input type="number"
  99. placeholder="请输入零售价"
  100. @mousewheel.native.prevent
  101. :disabled="pageDisabled"
  102. v-model.trim="form.discountPrice"
  103. style="width: 400px"></el-input>
  104. </el-form-item>
  105. <el-form-item label="商品团购价"
  106. prop="groupPurchasePrice">
  107. <el-input type="number"
  108. placeholder="请输入商品团购价"
  109. @mousewheel.native.prevent
  110. :disabled="pageDisabled"
  111. v-model.trim="form.groupPurchasePrice"
  112. style="width: 400px"></el-input>
  113. </el-form-item>
  114. <el-form-item label="学员是否展示"
  115. prop="clientShow">
  116. <el-select v-model="form.clientShow"
  117. placeholder="请选择学员是否展示"
  118. style="width: 400px !important;">
  119. <el-option label="是"
  120. :value="1"></el-option>
  121. <el-option label="否"
  122. :value="0"></el-option>
  123. </el-select>
  124. </el-form-item>
  125. <el-form-item label="教务端是否展示"
  126. prop="educationalShow">
  127. <el-select v-model="form.educationalShow"
  128. placeholder="请选择教务端是否展示"
  129. style="width: 400px !important;">
  130. <el-option label="是"
  131. :value="1"></el-option>
  132. <el-option label="否"
  133. :value="0"></el-option>
  134. </el-select>
  135. </el-form-item>
  136. <el-form-item label="乐团是否展示"
  137. prop="musicGroupShow">
  138. <el-select v-model="form.musicGroupShow"
  139. placeholder="请选择乐团是否展示"
  140. style="width: 400px !important;">
  141. <el-option label="是"
  142. :value="1"></el-option>
  143. <el-option label="否"
  144. :value="0"></el-option>
  145. </el-select>
  146. </el-form-item>
  147. <el-form-item label="是否库存预警"
  148. prop="stockWarning">
  149. <el-select v-model="form.stockWarning"
  150. placeholder="请选择库存预警"
  151. :disabled="pageDisabled"
  152. style="width: 400px !important;">
  153. <el-option label="是"
  154. :value="1"></el-option>
  155. <el-option label="否"
  156. :value="0"></el-option>
  157. </el-select>
  158. </el-form-item>
  159. <el-form-item label="商品图片"
  160. prop="image">
  161. <el-upload class="avatar-uploader"
  162. action="/api-web/uploadFile"
  163. accept=".jpg, .jpeg, .png"
  164. :headers="headers"
  165. :disabled="pageDisabled"
  166. :show-file-list="false"
  167. :on-success="handleAvatarSuccess"
  168. :before-upload="beforeAvatarUpload">
  169. <img v-if="form.image"
  170. :src="form.image"
  171. class="avatar">
  172. <i v-else
  173. class="el-icon-plus avatar-uploader-icon"></i>
  174. </el-upload>
  175. </el-form-item>
  176. <el-form-item label="商品描述"
  177. prop="brief">
  178. <el-input type="textarea"
  179. v-model.trim="form.brief"
  180. :disabled="pageDisabled"
  181. style="width: 400px"></el-input>
  182. </el-form-item>
  183. <el-form-item label="商品详情"
  184. prop="desc">
  185. <el-input type="textarea"
  186. v-model.trim="form.desc"
  187. :disabled="pageDisabled"
  188. style="width: 400px"></el-input>
  189. </el-form-item>
  190. <el-form-item v-if="!pageDisabled">
  191. <el-button @click="onSubmit('form')"
  192. type="primary">立即{{ pageType == "create" ? '创建' : '修改' }}</el-button>
  193. <el-button @click="onReSet('form')">重置</el-button>
  194. </el-form-item>
  195. </el-form>
  196. </div>
  197. </div>
  198. </template>
  199. <script>
  200. import {
  201. categoryListTree,
  202. goodsAdd,
  203. goodsUpdate,
  204. goodsSingleQuery
  205. } from '@/api/businessManager'
  206. import {
  207. getToken
  208. } from '@/utils/auth'
  209. import { goodsType, stockType } from '@/utils/searchArray'
  210. let validPrice = (rule, value, callback) => {
  211. if (value == '' && typeof value == 'string' || value == null) {
  212. callback(new Error('请输入金额'))
  213. } else if (value < 0) {
  214. callback(new Error('输入金额必须大于或等于0'))
  215. } else if (value >= 100000) {
  216. callback(new Error('输入金额必须小于100000'))
  217. } else {
  218. callback()
  219. }
  220. }
  221. let validStock = (rule, value, callback) => {
  222. if (value == '' && typeof value == 'string' || value == null) {
  223. callback(new Error('请输入库存'))
  224. } else if (value < 0) {
  225. callback(new Error('库存数量必须大于或等于0'))
  226. } else {
  227. callback()
  228. }
  229. }
  230. export default {
  231. name: 'shopOperation',
  232. data () {
  233. return {
  234. goodsType: goodsType,
  235. stockType: stockType,
  236. categoryList: [],
  237. pageType: null,
  238. pageTitle: {
  239. 'create': '添加',
  240. 'update': '修改',
  241. 'look': '查看',
  242. },
  243. pageDisabled: false,
  244. headers: {
  245. Authorization: getToken()
  246. },
  247. form: {
  248. sn: null,
  249. brand: null,
  250. supplyChannel: null,
  251. name: null,
  252. type: null,
  253. goodsCategoryId: null,
  254. specification: null,
  255. stockCount: null,
  256. taxStockCount: null,
  257. stockType: null,
  258. marketPrice: null,
  259. discountPrice: null,
  260. groupPurchasePrice: null,
  261. clientShow: null,
  262. educationalShow: null,
  263. musicGroupShow: null,
  264. stockWarning: null,
  265. image: null,
  266. brief: null,
  267. desc: null
  268. },
  269. rules: {
  270. sn: [{ required: true, message: '请输入商品货号', trigger: 'blur' }],
  271. brand: [{
  272. required: true,
  273. message: '请输入品牌',
  274. trigger: 'blur'
  275. },
  276. {
  277. min: 2,
  278. max: 30,
  279. message: '长度在 2 到 30 个字符',
  280. trigger: 'blur'
  281. }
  282. ],
  283. supplyChannel: [
  284. { required: true, message: '请输入备查货号', trigger: 'blur' }
  285. ],
  286. name: [{
  287. required: true,
  288. message: '请输入商品名称',
  289. trigger: 'blur'
  290. },
  291. {
  292. min: 2,
  293. max: 30,
  294. message: '长度在 2 到 30 个字符',
  295. trigger: 'blur'
  296. }
  297. ],
  298. type: [{
  299. required: true,
  300. message: '请选择商品分类',
  301. trigger: 'change'
  302. }],
  303. goodsCategoryId: [{
  304. required: true,
  305. message: '请选择商品类型',
  306. trigger: 'change'
  307. }],
  308. specification: [{
  309. required: true,
  310. message: '请输入商品型号',
  311. trigger: 'blur'
  312. },
  313. {
  314. min: 2,
  315. max: 30,
  316. message: '长度在 2 到 30 个字符',
  317. trigger: 'blur'
  318. }
  319. ],
  320. stockCount: [
  321. { required: true, validator: validStock, trigger: 'blur' }
  322. ],
  323. taxStockCount: [
  324. { required: true, validator: validStock, trigger: 'blur' }
  325. ],
  326. stockType: [
  327. { required: true, message: '请选择库存类型', trigger: 'change' }
  328. ],
  329. marketPrice: [{
  330. required: true,
  331. validator: validPrice,
  332. trigger: 'blur'
  333. }],
  334. discountPrice: [{
  335. required: true,
  336. validator: validPrice,
  337. trigger: 'blur'
  338. }],
  339. groupPurchasePrice: [{
  340. required: true,
  341. validator: validPrice,
  342. trigger: 'blur'
  343. }],
  344. clientShow: [
  345. { required: true, message: '请选择学员是否展示', trigger: 'change' }
  346. ],
  347. educationalShow: [
  348. { required: true, message: '请选择教务端是否展示', trigger: 'change' }
  349. ],
  350. musicGroupShow: [
  351. { required: true, message: '请选择乐团是否展示', trigger: 'change' }
  352. ],
  353. stockWarning: [
  354. { required: true, message: '请选择是否库存预警', trigger: 'change' }
  355. ],
  356. image: [{
  357. required: true,
  358. message: '请选择图片',
  359. trigger: 'blur'
  360. }],
  361. brief: [{
  362. required: true,
  363. message: '请输入商品描述',
  364. trigger: 'blur'
  365. }],
  366. desc: [{
  367. required: true,
  368. message: '请输入商品详情',
  369. trigger: 'blur'
  370. }]
  371. },
  372. Fsearch: null,
  373. Frules: null,
  374. imageWidthM: 400,
  375. imageHeightM: 400
  376. }
  377. },
  378. mounted () {
  379. this.init()
  380. },
  381. methods: {
  382. init () {
  383. let query = this.$route.query
  384. if (query.paramInfo) {
  385. let paramInfo = JSON.parse(query.paramInfo)
  386. this.pageType = paramInfo.type
  387. this.id = paramInfo.id
  388. }
  389. this.pageDisabled = this.pageType == 'look' ? true : false
  390. this.getList()
  391. this.getCatagory()
  392. },
  393. onSubmit (formName) {
  394. this.$refs[formName].validate((valid) => {
  395. if (valid) {
  396. if (this.pageType == 'create') {
  397. if (this.form.id) { // 判断有没有Id,如果有则删除
  398. delete this.form.id
  399. }
  400. this.form.status = 'NO' // 默认上架
  401. goodsAdd(this.form).then(res => {
  402. this.messageTips('添加', res)
  403. })
  404. } else if (this.pageType == 'update') {
  405. goodsUpdate(this.form).then(res => {
  406. this.messageTips('修改', res)
  407. })
  408. }
  409. } else {
  410. this.$nextTick(() => {
  411. let isError = document.getElementsByClassName('is-error')
  412. isError[0].scrollIntoView({
  413. block: 'center',
  414. behavior: 'smooth',
  415. })
  416. })
  417. return false
  418. }
  419. })
  420. },
  421. messageTips (title, res) {
  422. if (res.code == 200) {
  423. this.$message.success(title + '成功')
  424. this.$router.push({
  425. path: '/shopManager/shopManager',
  426. query: {
  427. pageInfo: this.Frules,
  428. searchForm: this.Fsearch
  429. }
  430. })
  431. } else {
  432. this.$message.error(res.msg)
  433. }
  434. },
  435. onCancel () {
  436. this.$router.push({
  437. path: '/shopManager/shopManager'
  438. })
  439. },
  440. onReSet (formName) {
  441. this.$refs[formName].resetFields()
  442. },
  443. getList () {
  444. if (this.pageType == 'create') {
  445. this.form = {
  446. sn: null,
  447. brand: null,
  448. supplyChannel: null,
  449. name: null,
  450. type: null,
  451. goodsCategoryId: null,
  452. specification: null,
  453. stockCount: null,
  454. taxStockCount: null,
  455. stockType: null,
  456. marketPrice: null,
  457. discountPrice: null,
  458. groupPurchasePrice: null,
  459. clientShow: null,
  460. educationalShow: null,
  461. musicGroupShow: null,
  462. stockWarning: null,
  463. image: null,
  464. brief: null,
  465. desc: null
  466. }
  467. if (this.$refs['form']) {
  468. this.$refs['form'].resetFields();
  469. }
  470. } else {
  471. goodsSingleQuery(this.id).then(res => {
  472. if (res.code == 200) {
  473. let result = res.data
  474. this.form = {
  475. id: result.id,
  476. sn: result.sn,
  477. brand: result.brand,
  478. supplyChannel: result.supplyChannel,
  479. name: result.name,
  480. type: result.type,
  481. goodsCategoryId: result.goodsCategoryId,
  482. specification: result.specification,
  483. stockCount: result.stockCount,
  484. taxStockCount: result.taxStockCount,
  485. stockType: result.stockType,
  486. marketPrice: result.marketPrice,
  487. discountPrice: result.discountPrice,
  488. groupPurchasePrice: result.groupPurchasePrice,
  489. clientShow: result.clientShow,
  490. educationalShow: result.educationalShow,
  491. musicGroupShow: result.musicGroupShow,
  492. stockWarning: result.stockWarning,
  493. image: result.image,
  494. brief: result.brief,
  495. desc: result.desc
  496. }
  497. }
  498. })
  499. }
  500. },
  501. getCatagory () {
  502. categoryListTree({
  503. delFlag: 0,
  504. rows: 9999
  505. }).then(res => {
  506. let result = res.data
  507. if (res.code == 200) {
  508. let tempArray = []
  509. result.rows.forEach(row => {
  510. tempArray.push({
  511. label: row.name,
  512. value: row.id
  513. })
  514. })
  515. this.categoryList = tempArray
  516. }
  517. })
  518. },
  519. handleAvatarSuccess (res, file) {
  520. this.form.image = res.data.url
  521. },
  522. beforeAvatarUpload (file) {
  523. const imageType = {
  524. 'image/png': true,
  525. 'image/jpeg': true
  526. }
  527. const isImage = imageType[file.type]
  528. const isLt2M = file.size / 1024 / 1024 < 2
  529. const imageWidth = this.imageWidthM
  530. const imageHeigh = this.imageHeightM
  531. const _URL = window.URL || window.webkitURL
  532. const isSize = new Promise((resolve, reject) => {
  533. const img = new Image()
  534. img.onload = function () {
  535. if (imageWidth && imageHeigh) {
  536. this.width === imageWidth && this.height === imageHeigh ? resolve() : reject(`请上传${imageWidth}x${imageHeigh}尺寸图片`)
  537. } else if (imageWidth && !imageHeigh) {
  538. this.width === imageWidth ? resolve() : reject(`请上传宽为${imageWidth}的图片`)
  539. } else if (!imageWidth && imageHeigh) {
  540. this.height === imageHeigh ? resolve() : reject(`请上传高为${imageHeigh}的图片`)
  541. }
  542. else {
  543. resolve()
  544. }
  545. }
  546. img.src = _URL.createObjectURL(file)
  547. }).then(
  548. () => {
  549. return file
  550. },
  551. (src) => {
  552. this.$message.error(src);
  553. this.uploadImgLoading = false
  554. return Promise.reject()
  555. }
  556. )
  557. console.log(isSize)
  558. if (!isImage) {
  559. this.$message.error('只能上传图片格式!')
  560. }
  561. if (!isLt2M) {
  562. this.$message.error('上传头像图片大小不能超过 2MB!')
  563. }
  564. return isImage && isLt2M && isSize;
  565. },
  566. }
  567. }
  568. </script>
  569. <style lang="scss" scoped>
  570. .el-button--primary {
  571. background: #14928a;
  572. border-color: #14928a;
  573. color: #fff;
  574. &:hover,
  575. &:active,
  576. &:focus {
  577. background: #14928a;
  578. border-color: #14928a;
  579. color: #fff;
  580. }
  581. }
  582. .el-row {
  583. margin-top: 40px;
  584. }
  585. .el-col {
  586. display: flex;
  587. align-items: center;
  588. margin-bottom: 20px;
  589. justify-content: flex-end;
  590. margin-right: 50%;
  591. }
  592. .el-input-group {
  593. width: 200px;
  594. margin: 0 20px;
  595. }
  596. /deep/.el-tree-node__content {
  597. height: 40px !important;
  598. }
  599. /deep/.avatar-uploader .el-upload {
  600. border: 1px dashed #d9d9d9;
  601. border-radius: 6px;
  602. cursor: pointer;
  603. position: relative;
  604. overflow: hidden;
  605. }
  606. .avatar-uploader .el-upload:hover {
  607. border-color: #409eff;
  608. }
  609. .avatar-uploader-icon {
  610. font-size: 28px;
  611. color: #8c939d;
  612. width: 120px;
  613. height: 120px;
  614. line-height: 120px;
  615. text-align: center;
  616. }
  617. .avatar {
  618. width: 120px;
  619. height: 120px;
  620. display: block;
  621. }
  622. </style>