shopOperation.vue 19 KB

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