form-club-device.vue 15 KB

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