form-club-device.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. <template>
  2. <div class="club-device">
  3. <template v-for="formItem in formList">
  4. <div :key="formItem.uid">
  5. <el-form :model="formItem" :rules="rules" ref="form">
  6. <el-form-item prop="productName" :label="`设备名称${formItem.uuid}:`">
  7. <el-select
  8. v-model="formItem.productName"
  9. filterable
  10. allow-create
  11. placeholder="请输入新设备名称或选择已有设备"
  12. @change="onProductNameChange(formItem, $event)"
  13. >
  14. <el-option
  15. v-for="item in deviceList"
  16. :key="item.productTypeId"
  17. :label="item.name"
  18. :value="item.productTypeId"
  19. />
  20. </el-select>
  21. </el-form-item>
  22. <el-form-item prop="productImage" label="设备图片:">
  23. <br />
  24. <el-input v-show="false" v-model="formItem.productImage"></el-input>
  25. <SimpleUploadImage
  26. :disabled="Boolean(formItem.productTypeId)"
  27. :limit="1"
  28. :image-list="formItem.productImageList"
  29. :before-upload="beforeProductImageUpload"
  30. @success="uploadProductImageSuccess(formItem, $event)"
  31. @remove="handleProductImageRemove(formItem, $event)"
  32. />
  33. </el-form-item>
  34. <el-form-item label="所属品牌:" prop="brandId">
  35. <el-select v-model="formItem.brandId" placeholder="请选择品牌">
  36. <el-option
  37. v-for="item in brandList"
  38. :key="item.id"
  39. :label="item.name"
  40. :value="item.id"
  41. />
  42. </el-select>
  43. </el-form-item>
  44. <el-form-item prop="purchaseWay" label="购买渠道:">
  45. <el-input
  46. placeholder="请输入购买渠道"
  47. v-model="formItem.purchaseWay"
  48. ></el-input>
  49. </el-form-item>
  50. <el-form-item prop="invoiceImage" label="发票:">
  51. <br />
  52. <el-input v-show="false" v-model="formItem.invoiceImage"></el-input>
  53. <SimpleUploadImage
  54. :limit="1"
  55. :image-list="formItem.invoiceImageList"
  56. :before-upload="beforeInvoiceImageUpload"
  57. @success="uploadInvoiceImageSuccess(formItem, $event)"
  58. @remove="handleInvoiceImageRemove(formItem, $event)"
  59. />
  60. </el-form-item>
  61. <el-form-item prop="snCode" label="设备SN码:">
  62. <el-input
  63. placeholder="请输入设备SN码"
  64. v-model="formItem.snCode"
  65. ></el-input>
  66. </el-form-item>
  67. <el-form-item prop="paramList" label="设备参数:">
  68. <br />
  69. <div class="device-param-list">
  70. <span class="add-param" @click="insertParam(formItem)"
  71. >添加参数</span
  72. >
  73. <template v-for="(param, index) in formItem.paramList">
  74. <div :key="index">
  75. <div class="param flex justify-between mb-4">
  76. <el-input
  77. style="width: 40%"
  78. placeholder="例如:品牌"
  79. class="mr-2"
  80. v-model="param.paramName"
  81. ></el-input>
  82. <el-input
  83. placeholder="请输入参数信息"
  84. v-model="param.paramContent"
  85. ></el-input>
  86. <span
  87. class="remove el-icon-close"
  88. @click="removeParam(formItem, index)"
  89. v-if="formItem.paramList.length > 4"
  90. ></span>
  91. </div>
  92. </div>
  93. </template>
  94. </div>
  95. </el-form-item>
  96. </el-form>
  97. <el-divider></el-divider>
  98. </div>
  99. </template>
  100. <div class="add-device" @click="insertOne">
  101. <div class="add-icon"></div>
  102. 添加设备
  103. </div>
  104. </div>
  105. </template>
  106. <script>
  107. import SimpleUploadImage from '@/components/SimpleUploadImage'
  108. import { mapGetters } from 'vuex'
  109. export default {
  110. components: {
  111. SimpleUploadImage,
  112. },
  113. data() {
  114. const productNameValidate = (rule, value, callback) => {
  115. if (value.toString().length > 50) {
  116. callback(new Error('设备名称长度需要在50个字符内'))
  117. } else {
  118. callback()
  119. }
  120. }
  121. return {
  122. uuid: 0, // 表单id
  123. productImageList: [],
  124. rules: {
  125. productName: [
  126. { required: true, message: '设备名称不能为空', trigger: ['change'] },
  127. { validator: productNameValidate, trigger: ['change'] },
  128. ],
  129. productImage: [
  130. { required: true, message: '设备图片不能为空', trigger: ['change'] },
  131. ],
  132. brandId: [
  133. { required: true, message: '所属品牌不能为空', trigger: ['change'] },
  134. ],
  135. snCode: [
  136. { required: true, message: '设备SN码不能为空', trigger: ['blur'] },
  137. ],
  138. paramList: [{ required: true, message: '参数不能为空' }],
  139. },
  140. formList: [],
  141. brandList: [],
  142. deviceList: [],
  143. }
  144. },
  145. computed: {
  146. ...mapGetters(['authUserId']),
  147. },
  148. created() {
  149. this.fetchBrandList()
  150. this.fetchDeviceList()
  151. this.initFormList()
  152. },
  153. methods: {
  154. // 表单验证
  155. validate() {
  156. this.$emit('step', this.formatFormList())
  157. return Promise.all(this.$refs.form.map((item) => item.validate()))
  158. },
  159. formatFormList() {
  160. const list = []
  161. this.formList.forEach((formItem) => {
  162. const obj = {}
  163. obj.productImage = formItem.productImage
  164. obj.productName = formItem.productName
  165. obj.snCode = formItem.snCode
  166. obj.brandId = formItem.brandId
  167. obj.productTypeId = formItem.productTypeId
  168. obj.purchaseWay = formItem.purchaseWay
  169. obj.invoiceImage = formItem.invoiceImage
  170. obj.paramList = formItem.paramList
  171. list.push(obj)
  172. })
  173. return list
  174. },
  175. generateFormData() {
  176. return {
  177. uuid: ++this.uuid,
  178. authUserId: '',
  179. authId: '', // 授权id
  180. createBy: '', // 创建人id
  181. // 设备参数列表
  182. paramList: this.initParams(),
  183. productId: '', // 授权设备id
  184. productImage: '', // 设备图片
  185. productName: '', // 设备名称
  186. snCode: '', // 设备SN码
  187. brandId: '',
  188. productTypeId: '',
  189. purchaseWay: '', // 购买渠道
  190. invoiceImage: '', // 发票
  191. productImageList: [],
  192. invoiceImageList: [],
  193. }
  194. },
  195. generageProductParam() {
  196. return {
  197. paramContent: '',
  198. paramName: '',
  199. }
  200. },
  201. initParams() {
  202. const list = []
  203. for (let i = 0; i < 4; i++) {
  204. list.push(this.generageProductParam())
  205. }
  206. return list
  207. },
  208. insertParam(formItem) {
  209. formItem.paramList.push(this.generateFormData())
  210. },
  211. removeParam(formItem, index) {
  212. formItem.paramList.splice(index, 1)
  213. },
  214. initFormList() {
  215. this.formList.push(this.generateFormData())
  216. console.log(this.formList)
  217. },
  218. insertOne() {
  219. this.formList.push(this.generateFormData())
  220. },
  221. removeOne() {},
  222. onProductNameChange(formItem, value) {
  223. if (typeof value === 'number') {
  224. formItem.productTypeId = value
  225. const deviceInfo = this.deviceList.find(
  226. (item) => item.productTypeId === value
  227. )
  228. formItem.productImage = deviceInfo.image
  229. formItem.productImageList = [{ name: '', url: deviceInfo.image }]
  230. } else {
  231. formItem.productTypeId = ''
  232. formItem.productImage = ''
  233. formItem.productImageList = []
  234. }
  235. },
  236. // 获取品牌列表
  237. async fetchBrandList() {
  238. try {
  239. const res = await this.$http.api.fetchBrandList({
  240. type: 3,
  241. authUserId: this.authUserId,
  242. })
  243. this.brandList = res.data
  244. } catch (error) {
  245. console.log(error)
  246. }
  247. },
  248. // 获取设备列表
  249. async fetchDeviceList() {
  250. try {
  251. const res = await this.$http.api.fetchProductSelectList({
  252. authUserId: this.authUserId,
  253. })
  254. this.deviceList = res.data
  255. } catch (error) {
  256. console.log(error)
  257. }
  258. },
  259. // 产品图片上传
  260. beforeProductImageUpload(file) {
  261. const flag = file.size / 1024 / 1024 < 1
  262. if (!flag) {
  263. this.$message.error('上传产品图片大小不能超过 1MB!')
  264. }
  265. return flag
  266. },
  267. uploadProductImageSuccess(formItem, { response, file, fileList }) {
  268. formItem.productImageList = fileList
  269. formItem.productImage = response.data
  270. },
  271. handleProductImageRemove(formItem, { file, fileList }) {
  272. formItem.productImageList = fileList
  273. formItem.productImage = ''
  274. },
  275. // 发票上传
  276. beforeInvoiceImageUpload(file) {
  277. const flag = file.size / 1024 / 1024 < 1
  278. if (!flag) {
  279. this.$message.error('发票图片大小不能超过 1MB!')
  280. }
  281. return flag
  282. },
  283. uploadInvoiceImageSuccess(formItem, { response, file, fileList }) {
  284. formItem.invoiceImageList = fileList
  285. formItem.invoiceImage = response.data
  286. },
  287. handleInvoiceImageRemove(formItem, { file, fileList }) {
  288. formItem.invoiceImageList = fileList
  289. formItem.invoiceImage = ''
  290. },
  291. },
  292. }
  293. </script>
  294. <style lang="scss" scoped>
  295. // pc端
  296. @media screen and (min-width: 768px) {
  297. .el-select {
  298. width: 100%;
  299. }
  300. .device-param-list {
  301. position: relative;
  302. .add-param {
  303. position: absolute;
  304. cursor: pointer;
  305. top: -40px;
  306. right: 0;
  307. text-decoration: underline;
  308. font-size: 14px;
  309. @include themify($themes) {
  310. color: themed('color');
  311. }
  312. }
  313. .param {
  314. position: relative;
  315. .remove {
  316. position: absolute;
  317. right: 0;
  318. top: 0;
  319. width: 20px;
  320. height: 20px;
  321. background: #f94b4b;
  322. border-radius: 2px;
  323. cursor: pointer;
  324. color: #fff;
  325. font-size: 14px;
  326. text-align: center;
  327. line-height: 20px;
  328. }
  329. }
  330. }
  331. .add-device {
  332. display: flex;
  333. justify-content: center;
  334. align-items: center;
  335. width: 162px;
  336. height: 46px;
  337. border-radius: 4px;
  338. box-sizing: border-box;
  339. font-size: 18px;
  340. margin: 0 auto;
  341. cursor: pointer;
  342. @include themify($themes) {
  343. border: 1px solid themed('color');
  344. color: themed('color');
  345. }
  346. .add-icon {
  347. width: 20px;
  348. height: 20px;
  349. position: relative;
  350. margin-right: 16px;
  351. &::before,
  352. &::after {
  353. position: absolute;
  354. width: 3px;
  355. height: 20px;
  356. left: 50%;
  357. top: 50%;
  358. transform: translate(-50%, -50%);
  359. border-radius: 1px;
  360. content: '';
  361. display: block;
  362. @include themify($themes) {
  363. background: themed('color');
  364. }
  365. }
  366. &::after {
  367. transform: translate(-50%, -50%) rotateZ(90deg);
  368. }
  369. }
  370. }
  371. }
  372. // 移动端
  373. @media screen and (max-width: 768px) {
  374. ::v-deep {
  375. .el-form-item__label {
  376. font-size: 3.4vw;
  377. }
  378. }
  379. .el-select {
  380. width: 100%;
  381. }
  382. .device-param-list {
  383. position: relative;
  384. .add-param {
  385. position: absolute;
  386. cursor: pointer;
  387. top: -40px;
  388. right: 0;
  389. font-size: 3.4vw;
  390. @include themify($themes) {
  391. color: themed('color');
  392. }
  393. }
  394. .param {
  395. position: relative;
  396. .remove {
  397. position: absolute;
  398. right: 0;
  399. top: 0;
  400. width: 4.4vw;
  401. height: 4.4vw;
  402. background: #f94b4b;
  403. border-radius: 0.2vw;
  404. cursor: pointer;
  405. color: #fff;
  406. font-size: 3.4vw;
  407. text-align: center;
  408. line-height: 4.4vw;
  409. }
  410. }
  411. }
  412. .add-device {
  413. display: flex;
  414. justify-content: center;
  415. align-items: center;
  416. width: 31vw;
  417. height: 8.8vw;
  418. border-radius: 0.4vw;
  419. box-sizing: border-box;
  420. font-size: 3.4vw;
  421. margin: 0 auto;
  422. cursor: pointer;
  423. @include themify($themes) {
  424. border: 1px solid themed('color');
  425. color: themed('color');
  426. }
  427. .add-icon {
  428. width: 20px;
  429. height: 20px;
  430. position: relative;
  431. margin-right: 16px;
  432. &::before,
  433. &::after {
  434. position: absolute;
  435. width: 0.6vw;
  436. height: 4.1vw;
  437. left: 50%;
  438. top: 50%;
  439. transform: translate(-50%, -50%);
  440. border-radius: 1px;
  441. content: '';
  442. display: block;
  443. @include themify($themes) {
  444. background: themed('color');
  445. }
  446. }
  447. &::after {
  448. transform: translate(-50%, -50%) rotateZ(90deg);
  449. }
  450. }
  451. }
  452. }
  453. </style>