form-club-device.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  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" v-if="formType !== 'edit'">
  101. <div class="add-icon"></div>
  102. 添加设备
  103. </div>
  104. <SimpleDialog
  105. v-if="formType !== 'edit'"
  106. v-model="active"
  107. @confirm="active = false"
  108. :cancel="false"
  109. description="请慎重填写机构信息,认证通过后将无法更改!"
  110. :center="true"
  111. />
  112. </div>
  113. </template>
  114. <script>
  115. import SimpleUploadImage from '@/components/SimpleUploadImage'
  116. import { mapGetters } from 'vuex'
  117. export default {
  118. components: {
  119. SimpleUploadImage,
  120. },
  121. props: {
  122. formType: {
  123. type: String,
  124. default: 'add',
  125. },
  126. },
  127. data() {
  128. const productNameValidate = (rule, value, callback) => {
  129. if (value.toString().length > 50) {
  130. callback(new Error('设备名称长度需要在50个字符内'))
  131. } else {
  132. callback()
  133. }
  134. }
  135. return {
  136. active: true,
  137. uuid: 0, // 表单id
  138. productImageList: [],
  139. rules: {
  140. productName: [
  141. { required: true, message: '设备名称不能为空', trigger: ['change'] },
  142. { validator: productNameValidate, trigger: ['change'] },
  143. ],
  144. productImage: [
  145. { required: true, message: '设备图片不能为空', trigger: ['change'] },
  146. ],
  147. brandId: [
  148. { required: true, message: '所属品牌不能为空', trigger: ['change'] },
  149. ],
  150. snCode: [
  151. { required: true, message: '设备SN码不能为空', trigger: ['blur'] },
  152. ],
  153. paramList: [{ required: true, message: '参数不能为空' }],
  154. },
  155. formList: [],
  156. brandList: [],
  157. deviceList: [],
  158. }
  159. },
  160. computed: {
  161. ...mapGetters(['authUserId']),
  162. },
  163. created() {
  164. this.fetchBrandList()
  165. this.fetchDeviceList()
  166. this.initFormList()
  167. },
  168. methods: {
  169. // 表单验证
  170. validate() {
  171. this.$emit('step', this.formatFormList())
  172. return Promise.all(this.$refs.form.map((item) => item.validate()))
  173. },
  174. async init(formData) {
  175. console.log('formData', formData)
  176. const obj = {}
  177. const productImageList = [
  178. {
  179. name: '',
  180. url: formData?.productImage,
  181. },
  182. ]
  183. const invoiceImageList = [
  184. {
  185. name: '',
  186. url: formData.invoiceImage,
  187. },
  188. ]
  189. obj.uuid = ++this.uuid
  190. obj.productImageList = productImageList
  191. obj.invoiceImageList = invoiceImageList
  192. obj.productImage = formData.productImage
  193. obj.productName = formData.productName
  194. obj.snCode = formData.snCode
  195. obj.brandId = formData.brandId
  196. obj.productId = formData.productId
  197. obj.productTypeId = formData.productTypeId
  198. obj.purchaseWay = formData.purchaseWay
  199. obj.invoiceImage = formData.invoiceImage
  200. obj.paramList = formData.paramList
  201. this.formList.splice(0, 1, obj)
  202. console.log('formList', this.formList)
  203. },
  204. formatFormList() {
  205. const list = []
  206. this.formList.forEach((formItem) => {
  207. const obj = {}
  208. obj.productImage = formItem.productImage
  209. obj.productName = formItem.productName
  210. obj.snCode = formItem.snCode
  211. obj.brandId = formItem.brandId
  212. obj.productId = formItem.productId
  213. obj.source = 2
  214. obj.productTypeId = formItem.productTypeId
  215. obj.purchaseWay = formItem.purchaseWay
  216. obj.invoiceImage = formItem.invoiceImage
  217. obj.paramList = formItem.paramList
  218. list.push(obj)
  219. })
  220. return list
  221. },
  222. generateFormData() {
  223. return {
  224. uuid: ++this.uuid,
  225. authUserId: '',
  226. authId: '', // 授权id
  227. createBy: '', // 创建人id
  228. // 设备参数列表
  229. paramList: this.initParams(),
  230. productId: '', // 授权设备id
  231. productImage: '', // 设备图片
  232. productName: '', // 设备名称
  233. snCode: '', // 设备SN码
  234. brandId: '',
  235. productTypeId: '',
  236. purchaseWay: '', // 购买渠道
  237. invoiceImage: '', // 发票
  238. productImageList: [],
  239. invoiceImageList: [],
  240. }
  241. },
  242. generageProductParam() {
  243. return {
  244. paramContent: '',
  245. paramName: '',
  246. }
  247. },
  248. initParams() {
  249. const list = []
  250. for (let i = 0; i < 4; i++) {
  251. list.push(this.generageProductParam())
  252. }
  253. return list
  254. },
  255. insertParam(formItem) {
  256. formItem.paramList.push(this.generateFormData())
  257. },
  258. removeParam(formItem, index) {
  259. formItem.paramList.splice(index, 1)
  260. },
  261. initFormList() {
  262. this.formList.push(this.generateFormData())
  263. console.log(this.formList)
  264. },
  265. insertOne() {
  266. this.formList.push(this.generateFormData())
  267. },
  268. removeOne() {},
  269. onProductNameChange(formItem, value) {
  270. if (typeof value === 'number') {
  271. formItem.productTypeId = value
  272. const deviceInfo = this.deviceList.find(
  273. (item) => item.productTypeId === value
  274. )
  275. formItem.productImage = deviceInfo.image
  276. formItem.productImageList = [{ name: '', url: deviceInfo.image }]
  277. } else {
  278. formItem.productTypeId = ''
  279. formItem.productImage = ''
  280. formItem.productImageList = []
  281. }
  282. },
  283. // 获取品牌列表
  284. async fetchBrandList() {
  285. try {
  286. const res = await this.$http.api.fetchBrandList({
  287. type: 3,
  288. authUserId: this.authUserId,
  289. })
  290. this.brandList = res.data
  291. } catch (error) {
  292. console.log(error)
  293. }
  294. },
  295. // 获取设备列表
  296. async fetchDeviceList() {
  297. try {
  298. const res = await this.$http.api.fetchProductSelectList({
  299. authUserId: this.authUserId,
  300. })
  301. this.deviceList = res.data
  302. } catch (error) {
  303. console.log(error)
  304. }
  305. },
  306. // 产品图片上传
  307. beforeProductImageUpload(file) {
  308. const flag = file.size / 1024 / 1024 < 1
  309. if (!flag) {
  310. this.$message.error('上传产品图片大小不能超过 1MB!')
  311. }
  312. return flag
  313. },
  314. uploadProductImageSuccess(formItem, { response, file, fileList }) {
  315. formItem.productImageList = fileList
  316. formItem.productImage = response.data
  317. },
  318. handleProductImageRemove(formItem, { file, fileList }) {
  319. formItem.productImageList = fileList
  320. formItem.productImage = ''
  321. },
  322. // 发票上传
  323. beforeInvoiceImageUpload(file) {
  324. const flag = file.size / 1024 / 1024 < 1
  325. if (!flag) {
  326. this.$message.error('发票图片大小不能超过 1MB!')
  327. }
  328. return flag
  329. },
  330. uploadInvoiceImageSuccess(formItem, { response, file, fileList }) {
  331. formItem.invoiceImageList = fileList
  332. formItem.invoiceImage = response.data
  333. },
  334. handleInvoiceImageRemove(formItem, { file, fileList }) {
  335. formItem.invoiceImageList = fileList
  336. formItem.invoiceImage = ''
  337. },
  338. },
  339. }
  340. </script>
  341. <style lang="scss" scoped>
  342. // pc端
  343. @media screen and (min-width: 768px) {
  344. .el-select {
  345. width: 100%;
  346. }
  347. .device-param-list {
  348. position: relative;
  349. .add-param {
  350. position: absolute;
  351. cursor: pointer;
  352. top: -40px;
  353. right: 0;
  354. text-decoration: underline;
  355. font-size: 14px;
  356. @include themify($themes) {
  357. color: themed('color');
  358. }
  359. }
  360. .param {
  361. position: relative;
  362. .remove {
  363. position: absolute;
  364. right: 0;
  365. top: 0;
  366. width: 20px;
  367. height: 20px;
  368. background: #f94b4b;
  369. border-radius: 2px;
  370. cursor: pointer;
  371. color: #fff;
  372. font-size: 14px;
  373. text-align: center;
  374. line-height: 20px;
  375. }
  376. }
  377. }
  378. .add-device {
  379. display: flex;
  380. justify-content: center;
  381. align-items: center;
  382. width: 162px;
  383. height: 46px;
  384. border-radius: 4px;
  385. box-sizing: border-box;
  386. font-size: 18px;
  387. margin: 0 auto;
  388. cursor: pointer;
  389. @include themify($themes) {
  390. border: 1px solid themed('color');
  391. color: themed('color');
  392. }
  393. .add-icon {
  394. width: 20px;
  395. height: 20px;
  396. position: relative;
  397. margin-right: 16px;
  398. &::before,
  399. &::after {
  400. position: absolute;
  401. width: 3px;
  402. height: 20px;
  403. left: 50%;
  404. top: 50%;
  405. transform: translate(-50%, -50%);
  406. border-radius: 1px;
  407. content: '';
  408. display: block;
  409. @include themify($themes) {
  410. background: themed('color');
  411. }
  412. }
  413. &::after {
  414. transform: translate(-50%, -50%) rotateZ(90deg);
  415. }
  416. }
  417. }
  418. }
  419. // 移动端
  420. @media screen and (max-width: 768px) {
  421. ::v-deep {
  422. .el-form-item__label {
  423. font-size: 3.4vw;
  424. }
  425. }
  426. .el-select {
  427. width: 100%;
  428. }
  429. .device-param-list {
  430. position: relative;
  431. .add-param {
  432. position: absolute;
  433. cursor: pointer;
  434. top: -40px;
  435. right: 0;
  436. font-size: 3.4vw;
  437. @include themify($themes) {
  438. color: themed('color');
  439. }
  440. }
  441. .param {
  442. position: relative;
  443. .remove {
  444. position: absolute;
  445. right: 0;
  446. top: 0;
  447. width: 4.4vw;
  448. height: 4.4vw;
  449. background: #f94b4b;
  450. border-radius: 0.2vw;
  451. cursor: pointer;
  452. color: #fff;
  453. font-size: 3.4vw;
  454. text-align: center;
  455. line-height: 4.4vw;
  456. }
  457. }
  458. }
  459. .add-device {
  460. display: flex;
  461. justify-content: center;
  462. align-items: center;
  463. width: 31vw;
  464. height: 8.8vw;
  465. border-radius: 0.4vw;
  466. box-sizing: border-box;
  467. font-size: 3.4vw;
  468. margin: 0 auto;
  469. cursor: pointer;
  470. @include themify($themes) {
  471. border: 1px solid themed('color');
  472. color: themed('color');
  473. }
  474. .add-icon {
  475. width: 20px;
  476. height: 20px;
  477. position: relative;
  478. margin-right: 16px;
  479. &::before,
  480. &::after {
  481. position: absolute;
  482. width: 0.6vw;
  483. height: 4.1vw;
  484. left: 50%;
  485. top: 50%;
  486. transform: translate(-50%, -50%);
  487. border-radius: 1px;
  488. content: '';
  489. display: block;
  490. @include themify($themes) {
  491. background: themed('color');
  492. }
  493. }
  494. &::after {
  495. transform: translate(-50%, -50%) rotateZ(90deg);
  496. }
  497. }
  498. }
  499. }
  500. </style>