forms.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. <template>
  2. <!-- 表单 -->
  3. <div class="card_employee" :style="{maxHeight:beyondHeight}">
  4. <el-form ref="ruleForm" @submit.native.prevent :label-position="labelPosition" :model="ruleForm"
  5. :label-width="labelWidth">
  6. <el-row :gutter="10">
  7. <el-col :span="item.colWidth" v-for="(item, index) in formList" :key="index">
  8. <el-form-item class="card_independent" :label-width="item.labelWidth" :label="item.label" :prop="item.field"
  9. :rules="detail ? item.rules : {}" v-if="item.type === 'input'">
  10. <el-input :placeholder="item.placeholder" :disabled="item.disabled" :id="item.field"
  11. v-model="ruleForm[`${item.field}`]" auto-complete="new-password"
  12. :show-password="['newPassword','password'].includes(item.field) ? true : false"></el-input>
  13. <div class="unit_card" v-if="item.unit">{{item.unit}}</div>
  14. </el-form-item>
  15. <!-- 开关 -->
  16. <el-form-item class="card_independent" :label-width="item.labelWidth" :label="item.label" :prop="item.field"
  17. :rules="detail ? item.rules : {}" v-if="item.type === 'switch'">
  18. <div class="forms_switch">
  19. <el-switch v-model="ruleForm[`${item.field}`]" active-color="#13ce66"
  20. inactive-color="#ff4949"></el-switch>
  21. </div>
  22. </el-form-item>
  23. <!-- 扫描 -->
  24. <el-form-item class="card_independent" :label-width="item.labelWidth" :label="item.label" :prop="item.field"
  25. :rules="detail ? item.rules : {}" v-if="item.type === 'scan'">
  26. <el-input :placeholder="item.placeholder" :disabled="item.disabled" :id="item.field" v-model="inputs"
  27. @keyup.enter.native="serialNumber(item.field)" @focus="focus(item.field)" @input="iceRaftInput">
  28. <el-button slot="append" icon="el-icon-circle-plus icon_circle_btn"
  29. @click="serialNumber(item.field)"></el-button>
  30. </el-input>
  31. <div class="card_IceList" v-if="formIceTracing">
  32. <div class="ser_card_ial" v-for="(serial,num) in inputsList" :key="num">
  33. <div style="display: flex;align-items: center;">
  34. <div>{{num + 1}}</div>
  35. <div class="title_serial">{{serial}}</div>
  36. </div>
  37. <span class="del_serial" @click="delSerial(serial,num)">删除</span>
  38. </div>
  39. </div>
  40. </el-form-item>
  41. <div v-if="formIceTracing && item.type === 'scan'"
  42. :style="{height:scanHeight(inputsList.length),width:'100%'}"></div>
  43. <el-form-item :label-width="item.labelWidth" :label="item.label" :prop="item.field"
  44. :rules="detail ? item.rules : {}" v-if="item.type === 'textarea'">
  45. <el-input :maxlength="item.maxLenght" type="textarea" :rows="item.rowsHeight" :disabled="item.disabled"
  46. :id="item.field" :placeholder="item.placeholder" v-model="ruleForm[`${item.field}`]" />
  47. </el-form-item>
  48. <el-form-item :label-width="item.labelWidth" :label="item.label" :prop="item.field"
  49. :rules="detail ? item.rules : {}" v-if="item.type === 'select'">
  50. <el-select :id="item.field" v-model="ruleForm[`${item.field}`]" :placeholder="item.placeholder"
  51. :disabled="item.disabled" :multiple="item.multiple" style="width: 100%"
  52. @change="(params) => changeSelect(params,item.field)">
  53. <el-option v-for="(element, i) in item.options" :label="element.label" :value="`${element.value}`"
  54. :key="i">
  55. <span style="float: left">{{ element.label }}</span>
  56. <span style="float: right; color: #409EFF; font-size: 13px" v-if="element.IsBind">已绑定</span>
  57. </el-option>
  58. </el-select>
  59. </el-form-item>
  60. <el-form-item :label-width="item.labelWidth" :label="item.label" :prop="item.field"
  61. :rules="detail ? item.rules : {}" v-if="item.type === 'searchSelect'">
  62. <el-select :id="item.field" v-model="ruleForm[`${item.field}`]" v-loadmore="handleScroll" filterable remote
  63. :remote-method="(query) => remoteMethod(query, item.field)" :placeholder="item.placeholder"
  64. :disabled="item.disabled" style="width: 100%" @change="(row) => changeOption(row, item.field)">
  65. <el-option v-for="(element, i) in item.options" :label="element.label" :value="`${element.value}`"
  66. :key="i" />
  67. </el-select>
  68. </el-form-item>
  69. <el-form-item :label="item.label" :prop="item.field" :rules="detail ? item.rules : {}"
  70. v-if="item.type === 'cascader'">
  71. <el-cascader ref="organizerUnit" checkStrictly v-model="ruleForm[`${item.field}`]" :disabled="item.disabled"
  72. :options="item.options" :props="item.props" :show-all-levels="item.levels"
  73. @change="(query) => handleChange(query, item.field)">
  74. </el-cascader>
  75. </el-form-item>
  76. <el-form-item :label="item.label" :prop="item.field" :rules="detail ? item.rules : {}"
  77. v-if="item.type === 'radio'">
  78. <div style="display: flex;height: 40px;align-items: center;">
  79. <el-radio-group v-remove-hidden v-model="ruleForm[`${item.field}`]" :disabled="item.disabled"
  80. @input="radioInput">
  81. <el-radio v-for="(element, i) in item.options" :key="i"
  82. :label="element.value">{{element.label}}</el-radio>
  83. </el-radio-group>
  84. </div>
  85. </el-form-item>
  86. <el-form-item :label="item.label" :prop="item.field" :rules="detail ? item.rules : {}"
  87. v-if="item.type === 'time'">
  88. <el-date-picker type="date" value-format="yyyy-MM-dd" v-model="ruleForm[`${item.field}`]"
  89. :placeholder="item.placeholder" :disabled="item.disabled">
  90. </el-date-picker>
  91. </el-form-item>
  92. <el-form-item :label="item.label" :prop="item.field" :rules="detail ? item.rules : {}"
  93. v-if="item.type === 'section'">
  94. <el-date-picker align="center" v-model="ruleForm[`${item.field}`]" :disabled="item.disabled"
  95. type="datetimerange" value-format="yyyy-MM-dd HH:mm:ss" range-separator="至" start-placeholder="开始日期"
  96. end-placeholder="结束日期">
  97. </el-date-picker>
  98. </el-form-item>
  99. <div v-if="item.type === 'divider'">
  100. <div v-if="item.label">{{item.label}}</div>
  101. <el-divider></el-divider>
  102. </div>
  103. <div style="height: 40px;display: flex;align-items: center;" v-if="item.type === 'search'">
  104. <el-button size="small" type="primary" :loading="curLoading" :disabled="item.disabled"
  105. @click="numberSearch">{{item.label}}</el-button>
  106. </div>
  107. <div style="height: 10px;width: 100%;" v-if="item.type === 'dividingSlot'"></div>
  108. <el-form-item class="card_descriptions" :label="item.label" :prop="item.field"
  109. :rules="detail ? item.rules : {}" v-if="item.type === 'descriptions'">
  110. <span class="descriptions_title">{{ruleForm[`${item.field}`] || ''}}
  111. <span class="descriptions_badge center_in" v-if="item.field == 'name'">商户</span>
  112. <span v-if="item.field == 'quantity'">瓶</span>
  113. </span>
  114. </el-form-item>
  115. <el-form-item class="card_descriptions" :label="item.label" :prop="item.field"
  116. :rules="detail ? item.rules : {}" v-if="item.type === 'nvarchar' || item.type === 'nvarcharil'">
  117. <span class="descriptions_title" v-if="item.type === 'nvarchar'">{{ruleForm[`${item.field}`]}}</span>
  118. <span class="descriptions_title" :style="{color: filterColor(ruleForm,item.options,item.field)}"
  119. v-else-if="item.type === 'nvarcharil'">{{initDictvalueil(ruleForm,item.options,item.field)}}</span>
  120. </el-form-item>
  121. <!-- 单张图片上传 -->
  122. <el-form-item :class="item.crosswise ? '' : 'card_fuel_gas'" :label="item.label" :prop="item.field"
  123. :rules="detail ? item.rules : {}" v-if="item.type === 'singleUpload'">
  124. <el-upload class="avatar-uploader" action="#" :show-file-list="false" :disabled="item.disabled"
  125. :http-request="(params) => singleUpload(params,item.field)">
  126. <img v-if="ruleForm[`${item.field}`]" :src="$baseUrl + ruleForm[`${item.field}`]" class="avatar">
  127. <i v-else class="el-icon-plus avatar-uploader-icon"></i>
  128. </el-upload>
  129. </el-form-item>
  130. <!-- 可以上传多张 -->
  131. <div v-if="item.type === 'upload'">
  132. <div class="card_purple">
  133. <el-form-item ref="headimgUpload" :class="item.crosswise ? '' : 'card_fuel_gas'" class="margin-l-50"
  134. :label="item.label" :prop="item.field" :rules="detail ? item.rules : {}">
  135. <el-upload style="display: flex;" action="#" list-type="picture-card" :file-list="ruleForm.fileList"
  136. :disabled="item.disabled" :http-request="UploadImage" v-if="operationType != 'logs'">
  137. <i slot="default" class="el-icon-plus"></i>
  138. <div slot="file" slot-scope="{file}">
  139. <img class="el-upload-list__item-thumbnail" :src="file.url" alt="">
  140. <span class="el-upload-list__item-actions">
  141. <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
  142. <i class="el-icon-zoom-in"></i>
  143. </span>
  144. <span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file)">
  145. <i class="el-icon-delete"></i>
  146. </span>
  147. </span>
  148. </div>
  149. </el-upload>
  150. <div class="card_image" v-else>
  151. <div v-for="(item,index) in ruleForm.fileList" :key="index">
  152. <img class="avatar_image" :src="item.url" alt="" />
  153. <!-- <el-image class="avatar_image" :src="item.url" :preview-src-list="[item.url]">
  154. <div slot="placeholder" class="image-slot">
  155. 加载中<span class="dot">...</span>
  156. </div>
  157. </el-image> -->
  158. </div>
  159. </div>
  160. <el-dialog :visible.sync="dialogVisible" append-to-body>
  161. <img width="100%" :src="dialogImageUrl" alt="">
  162. </el-dialog>
  163. </el-form-item>
  164. </div>
  165. </div>
  166. </el-col>
  167. <el-col :span="20" :offset="4" v-if="iceBank && !formIceTracing">
  168. <div style="display: flex;flex-direction: column;">
  169. <div class="ser_card_ial margin_around" v-for="(serial,num) in inputsList" :key="num">
  170. <div style="display: flex;align-items: center;">
  171. <div>{{num + 1}}</div>
  172. <div class="title_serial">{{serial}}</div>
  173. </div>
  174. <span class="del_serial" @click="delSerial(serial,num)">删除</span>
  175. </div>
  176. </div>
  177. </el-col>
  178. </el-row>
  179. </el-form>
  180. </div>
  181. </template>
  182. <script>
  183. import {
  184. getFileToken,
  185. } from '@/api/login'
  186. import {
  187. getIceRaftCode,
  188. } from '@/api/iceRaft'
  189. export default {
  190. name: "forms",
  191. props: {
  192. // 表单tabel数据
  193. formNewList: {
  194. type: Array,
  195. default: () => [],
  196. },
  197. // 表单label宽度
  198. labelWidth: {
  199. type: String,
  200. default: () => '120px',
  201. },
  202. // 对齐方式
  203. labelPosition: {
  204. type: String,
  205. default: () => 'right',
  206. },
  207. // 绑定值
  208. ruleForm: {
  209. type: Object,
  210. default: () => {},
  211. },
  212. // 类型
  213. operationType: {
  214. type: String,
  215. default: () => '',
  216. },
  217. // 冰排冰库
  218. iceBank: {
  219. type: Boolean,
  220. default: () => false,
  221. },
  222. // 冰排追溯
  223. iceTracing: {
  224. type: Boolean,
  225. default: () => false,
  226. },
  227. // 表单冰排
  228. formIceTracing: {
  229. type: Boolean,
  230. default: () => false,
  231. },
  232. // 超出隐藏
  233. beyondHeight: {
  234. type: String,
  235. default: () => '530px',
  236. },
  237. },
  238. watch: {
  239. formNewList: {
  240. immediate: true, // 立即触发监听函数
  241. handler() {
  242. this.formList = this.formNewList;
  243. },
  244. },
  245. },
  246. data() {
  247. return {
  248. detail: true,
  249. formList: [],
  250. imageUrl: '',
  251. file: null,
  252. dialogImageUrl: '',
  253. dialogVisible: false,
  254. disabled: false,
  255. fileList: [],
  256. curLoading: false,
  257. inputs: "",
  258. timearr: [0, 0],
  259. isScanningGun: false,
  260. inputsList: [],
  261. typeField: '',
  262. }
  263. },
  264. methods: {
  265. //下拉框下拉事件
  266. changeSelect(row, field) {
  267. this.$forceUpdate()
  268. this.$emit("changeSelect", row, field);
  269. },
  270. // 搜索选择
  271. changeOption(row, field) {
  272. this.$emit("changeOption", row, field);
  273. },
  274. // 重置校验
  275. resetCheck() {
  276. const that = this
  277. if (that.iceTracing) {
  278. that.inputs = ''
  279. that.inputsList = []
  280. checkType(that.ruleForm.code)
  281. function checkType(value) {
  282. if (typeof value === 'string') {
  283. that.ruleForm.code = ''
  284. } else if (Array.isArray(value)) {
  285. that.ruleForm.code = []
  286. } else {
  287. that.ruleForm.code = []
  288. }
  289. }
  290. }
  291. that.$refs.ruleForm.resetFields();
  292. },
  293. // 单个图片上传
  294. singleUpload(file, value) {
  295. const loading = this.$loading({
  296. lock: true,
  297. text: 'Loading',
  298. spinner: 'el-icon-loading',
  299. background: 'rgba(0, 0, 0, 0.7)'
  300. });
  301. this.file = file.file;
  302. let formData = new FormData();
  303. formData.append('file', this.file);
  304. getFileToken(formData).then(res => {
  305. if (res.code == 200) {
  306. this.ruleForm[`${value}`] = res.data
  307. this.$forceUpdate()
  308. }
  309. loading.close();
  310. }).catch(e => {
  311. loading.close();
  312. this.$message.error('上传失败');
  313. })
  314. },
  315. // 上传文件
  316. UploadImage(file) {
  317. const loading = this.$loading({
  318. lock: true,
  319. text: 'Loading',
  320. spinner: 'el-icon-loading',
  321. background: 'rgba(0, 0, 0, 0.7)'
  322. });
  323. this.file = file.file;
  324. let formData = new FormData();
  325. formData.append('file', this.file);
  326. getFileToken(formData).then(res => {
  327. if (res.code == 200) {
  328. let arr1 = {
  329. uid: this.file.uid,
  330. url: res.data,
  331. }
  332. this.ruleForm.fileList.push(arr1)
  333. }
  334. loading.close();
  335. }).catch(e => {
  336. console.log(e, 23)
  337. loading.close();
  338. this.$message.error('上传失败');
  339. })
  340. },
  341. // 手机号搜索
  342. numberSearch() {
  343. let flag = false
  344. this.$refs['ruleForm'].validateField('phone', valid => {
  345. if (!valid) {
  346. this.curLoading = true
  347. this.$emit('numberSearch', this.ruleForm.phone)
  348. } else {
  349. console.log('error submit!!');
  350. return false;
  351. }
  352. });
  353. },
  354. // 单选选择
  355. radioInput(label) {
  356. this.$emit('radioInput', label)
  357. },
  358. // tag颜色获取
  359. filterColor(value, list, type) {
  360. let color = ''
  361. list.forEach(item => {
  362. if (value[type] === item.value) {
  363. color = item.bgcolor
  364. }
  365. })
  366. return color
  367. },
  368. // 普通类型文字匹配
  369. initDictvalueil(value, list, type) {
  370. let name = ''
  371. if (list) {
  372. list.forEach(item => {
  373. if (value[type] === item.value) {
  374. name = item.label
  375. }
  376. })
  377. }
  378. return name
  379. },
  380. handleScroll() {
  381. // console.log('触底了')
  382. this.$emit('handleScroll')
  383. },
  384. remoteMethod(val, type) {
  385. // console.log('远程搜索', val, type)
  386. this.$emit('remoteMethod', val, type)
  387. },
  388. // 删除
  389. handleRemove(file) {
  390. const filteredArr = this.ruleForm.fileList.filter(obj => obj.uid !== file.uid);
  391. this.ruleForm.fileList = filteredArr
  392. this.$forceUpdate()
  393. },
  394. // 查看
  395. handlePictureCardPreview(file) {
  396. this.dialogImageUrl = file.url;
  397. this.dialogVisible = true;
  398. },
  399. beforeAvatarUpload(file) {
  400. const isJPG = file.type === 'image/jpeg';
  401. const isLt2M = file.size / 1024 / 1024 < 2;
  402. if (!isJPG) {
  403. this.$message.error('上传头像图片只能是 JPG 格式!');
  404. }
  405. if (!isLt2M) {
  406. this.$message.error('上传头像图片大小不能超过 2MB!');
  407. }
  408. return isJPG && isLt2M;
  409. },
  410. // 添加编号
  411. serialNumber(field) {
  412. if (this.inputs) {
  413. getIceRaftCode(this.inputs).then(res => {
  414. if (res.code == 200) {
  415. this.inputsList.push(this.inputs)
  416. this.inputsList = this.uniqueArray(this.inputsList)
  417. this.inputs = ''
  418. this.ruleForm[`${field}`] = this.inputsList
  419. }
  420. })
  421. }
  422. },
  423. // 回车添加
  424. keydownBarcode(field) {
  425. if (this.inputs) {
  426. this.inputsList.push(this.inputs)
  427. this.inputsList = this.uniqueArray(this.inputsList)
  428. this.inputs = ''
  429. this.ruleForm[`${field}`] = this.inputsList
  430. }
  431. },
  432. // 输入
  433. iceRaftInput(value) {
  434. let arr = []
  435. arr.push(value)
  436. this.ruleForm.code = arr
  437. },
  438. // 去重
  439. uniqueArray(arr) {
  440. return [...new Set(arr)];
  441. },
  442. // 删除编号
  443. delSerial(value, index) {
  444. this.inputsList.splice(index, 1)
  445. this.ruleForm[`${this.typeField}`] = this.inputsList
  446. // this.ruleForm['code'].splice(index, 1);
  447. },
  448. focus(field) {
  449. this.typeField = field
  450. },
  451. // 级联选择器关闭
  452. handleChange(value, type) {
  453. if (this.$refs.organizerUnit) {
  454. this.$refs.organizerUnit[0].dropDownVisible = false
  455. }
  456. },
  457. scanHeight(num) {
  458. let arr = '0px'
  459. if (num < 4) {
  460. arr = num * 45 + 'px'
  461. } else {
  462. arr = 3 * 45 + 'px'
  463. }
  464. return arr
  465. },
  466. //子组件校验,传递到父组件
  467. validateForm() {
  468. let flag = null
  469. this.$refs['ruleForm'].validate(valid => {
  470. if (valid) {
  471. flag = true
  472. } else {
  473. flag = false
  474. }
  475. })
  476. return flag
  477. }
  478. }
  479. }
  480. </script>
  481. <style lang="scss" scoped>
  482. ::v-deep .el-cascader {
  483. width: 100% !important;
  484. }
  485. .card_purple ::v-deep .el-upload-list__item {
  486. width: 120px !important;
  487. height: 120px !important;
  488. }
  489. .card_purple ::v-deep .el-upload--picture-card {
  490. width: 120px !important;
  491. height: 120px !important;
  492. display: flex;
  493. justify-content: center;
  494. align-items: center;
  495. }
  496. .card_independent ::v-deep .icon_circle_btn {
  497. font-size: 20px;
  498. }
  499. .card_employee {
  500. // max-height: 530px;
  501. overflow-y: auto;
  502. overflow-x: hidden;
  503. }
  504. .margin-l-50 {
  505. margin-right: 50px;
  506. }
  507. .card_fuel_gas {
  508. display: flex;
  509. flex-direction: column;
  510. }
  511. ::v-deep .el-form-item__label {
  512. height: 40px !important;
  513. display: flex !important;
  514. align-items: center !important;
  515. justify-content: flex-end !important;
  516. line-height: unset !important;
  517. }
  518. .card_fuel_gas ::v-deep .el-form-item__label {
  519. width: 150px !important;
  520. text-align: left;
  521. // margin-bottom: 20px;
  522. }
  523. .card_descriptions {
  524. margin-bottom: 10px !important;
  525. }
  526. .card_fuel_gas ::v-deep .el-form-item__content {
  527. margin-left: 0px !important;
  528. }
  529. .card_purple {
  530. display: flex;
  531. }
  532. .descriptions_title {
  533. position: relative;
  534. }
  535. .descriptions_badge {
  536. position: absolute;
  537. width: fit-content;
  538. width: -webkit-fit-content;
  539. width: -moz-fit-content;
  540. top: -10px;
  541. right: -35px;
  542. color: #169BD5;
  543. font-size: 12px;
  544. line-height: 14px;
  545. padding: 2px;
  546. border: 1px solid #169BD5;
  547. }
  548. .unit_card {
  549. width: auto;
  550. padding-left: 10px;
  551. flex: none;
  552. }
  553. .card_independent ::v-deep .el-form-item__content {
  554. display: flex !important;
  555. }
  556. .card_image {
  557. display: flex;
  558. flex-direction: row;
  559. flex-wrap: wrap;
  560. }
  561. .avatar_image {
  562. width: 140px;
  563. height: 140px;
  564. border-radius: 6px;
  565. margin: 0 8px 8px 0;
  566. }
  567. .ser_card_ial {
  568. display: flex;
  569. justify-content: space-between;
  570. align-items: center;
  571. }
  572. .margin_around {
  573. margin: 5px 0px;
  574. }
  575. .title_serial {
  576. margin-left: 10px;
  577. }
  578. .del_serial {
  579. cursor: pointer;
  580. color: #F56C6C;
  581. }
  582. .card_IceList {
  583. display: flex;
  584. flex-direction: column;
  585. position: absolute;
  586. top: 60px;
  587. left: 0;
  588. right: 5px;
  589. padding: 0px 10px;
  590. max-height: 125px;
  591. overflow-y: auto;
  592. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  593. border-radius: 4px;
  594. }
  595. .forms_switch {
  596. height: 40px;
  597. }
  598. </style>