x-form.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. <template>
  2. <!-- 表单 -->
  3. <view style="margin: 0rpx 20rpx 0rpx 30rpx;">
  4. <u-form :model="model" :rules="rules" labelPosition="left" ref="uForm" labelWidth="70">
  5. <view v-for="(item,index) in list" :key="index">
  6. <u-form-item :required="item.required ? true : false" :label="item.label" :prop="item.field"
  7. v-if="item.type == 'input' && customerName(item)">
  8. <view class="card_form_item">
  9. <u-input v-model="model[`${item.field}`]" :clearable="item.clearable"
  10. :disabled="item.disabled ? true : false" :placeholder="item.placeholder"></u-input>
  11. <view class="card_sweep" v-if="['tamperProofLabel','code','drugBarCode'].includes(item.field)"
  12. @click="sweep(item.field)">
  13. <u-icon name="scan" size="18px"></u-icon>
  14. <span>扫一扫</span>
  15. </view>
  16. </view>
  17. </u-form-item>
  18. <u-form-item :required="item.required ? true : false" :label="item.label" :prop="item.field"
  19. v-else-if="item.type == 'drugBarCode'">
  20. <view class="card_form_item">
  21. <u-input v-model="model[`${item.field}`]" :clearable="item.clearable"
  22. :disabled="item.disabled ? true : false" :placeholder="item.placeholder">
  23. <template slot="suffix">
  24. <u-icon name="scan" size="24" @click="sweep(item.field)"></u-icon>
  25. </template>
  26. </u-input>
  27. <view class="add_cardil">
  28. <u-button class="custom-style" :loading="addloading" icon="plus"
  29. @click="sweep(item.field,true)"></u-button>
  30. </view>
  31. <!-- <view class="add_card center_in">
  32. <u-icon name="plus" size="18"></u-icon>
  33. </view> -->
  34. </view>
  35. </u-form-item>
  36. <u-form-item :required="item.required ? true : false" :label="item.label" :prop="item.field"
  37. v-else-if="item.type == 'select'">
  38. <view class="card_form_item">
  39. <u-input :placeholder="item.placeholder" suffixIcon="arrow-down"
  40. v-model="model[`${item.field}`]" @focus="change(item)"></u-input>
  41. </view>
  42. </u-form-item>
  43. <u-form-item :required="item.required ? true : false" :label="item.label" :prop="item.field"
  44. v-else-if="item.type == 'selectiveSearch'">
  45. <view class="card_form_item">
  46. <view class="card_search_gray frame" @click="changeil(item)" v-if="item.field == 'freezeClaim'">
  47. <span v-if="model[`${item.field}`].length">{{getTimeName(model[`${item.field}`])}}</span>
  48. <span class="title_gray" v-else>{{item.placeholder}}</span>
  49. <u-icon name="arrow-down" color="#c8c9cc" size="18"></u-icon>
  50. </view>
  51. <view class="card_search_gray frame" @click="changeil(item)" v-else>
  52. <span v-if="model[`${item.field}`]">{{model[`${item.field}`]}}</span>
  53. <span class="title_gray" v-else>{{item.placeholder}}</span>
  54. <u-icon name="arrow-down" color="#c8c9cc" size="18"></u-icon>
  55. </view>
  56. </view>
  57. </u-form-item>
  58. <u-form-item :required="item.required ? true : false" :label="item.label" :prop="item.field"
  59. v-else-if="item.type == 'selectil'">
  60. <view class="card_form_item">
  61. <u-input :placeholder="item.placeholder" suffixIcon="arrow-down"
  62. v-model="model[`${item.field}`]" @focus="changeil(item)"></u-input>
  63. </view>
  64. </u-form-item>
  65. <u-form-item :required="item.required ? true : false" :label="item.label" :prop="item.field"
  66. v-else-if="item.type == 'textarea'">
  67. <view class="card_form_item">
  68. <u-textarea v-model="model[`${item.field}`]" autoHeight
  69. :placeholder="item.placeholder"></u-textarea>
  70. </view>
  71. </u-form-item>
  72. <u-form-item :required="item.required ? true : false" :label="item.label" :prop="item.field"
  73. v-else-if="item.type == 'switch'">
  74. <view class="card_form_item">
  75. <u-switch v-model="model[`${item.field}`]" inactiveColor="#ff4949" activeColor="#13ce66"
  76. size="20"></u-switch>
  77. </view>
  78. </u-form-item>
  79. <u-form-item :required="item.required ? true : false" :label="item.label" :prop="item.field"
  80. v-else-if="item.type == 'upload' && !item.visible">
  81. <view class="card_form_item">
  82. <u-upload :fileList="item.fileList1" name="1" multiple :maxCount="10"
  83. @afterRead="afterRead($event, item)" @delete="deletePic($event, item)"></u-upload>
  84. </view>
  85. </u-form-item>
  86. <div class="card_drug_list" v-else-if="item.type == 'divider' && productData.length > 0">
  87. <x-productList :list="productData"></x-productList>
  88. </div>
  89. </view>
  90. </u-form>
  91. <u-picker :defaultIndex="findIndex(model[fieldType], columns[0])" :show="show" :columns="columns"
  92. keyName="label" @confirm="confirm($event, fieldType)" @cancel="cancel"></u-picker>
  93. <!-- 冷冻要求选择 -->
  94. <u-popup :show="freezeShow" @close="close">
  95. <view>
  96. <view class="space_between" style="height: 84rpx;">
  97. <view class="tittle_freeze gray_font" @click="freezeCancel">取消</view>
  98. <view class="tittle_freeze blue_font" @click="freezeConfirm">确定</view>
  99. </view>
  100. <view class="freeze_content">
  101. <view class="card_selected_list">
  102. <view class="hint_freeze" v-if="selectedData.length == 0">请选择冷冻要求</view>
  103. <view v-for="(item,index) in selectedData" :key="index">
  104. <u-tag :text="getTagName(item)" closable plain @close="closeFreeze(item)"></u-tag>
  105. </view>
  106. </view>
  107. <view class="fontsize_freeze" v-for="(item,index) in freezeList" :key="index"
  108. @click="freezeSelect(item)">
  109. <view>{{item.label}}</view>
  110. <view v-if="item.flag">
  111. <u-icon name="checkmark" color="#2979ff" size="22"></u-icon>
  112. </view>
  113. </view>
  114. </view>
  115. </view>
  116. </u-popup>
  117. </view>
  118. </template>
  119. <script>
  120. const ENV = require('@/.env.js')
  121. export default {
  122. name: 'x-form',
  123. props: {
  124. list: {
  125. type: Array,
  126. default () {
  127. return []
  128. }
  129. },
  130. model: {
  131. type: Object,
  132. default () {
  133. return {}
  134. }
  135. },
  136. rules: {
  137. type: Object,
  138. default () {
  139. return {}
  140. }
  141. },
  142. productData: {
  143. type: Array,
  144. default () {
  145. return []
  146. }
  147. },
  148. // 添加药品加载
  149. addloading: {
  150. type: Boolean,
  151. default () {
  152. return false
  153. }
  154. },
  155. },
  156. data() {
  157. return {
  158. show: false,
  159. columns: [],
  160. fieldType: '',
  161. fileList1: [],
  162. freezeShow: false,
  163. freezeList: [],
  164. selectedData: [],
  165. }
  166. },
  167. // 必须要在onReady生命周期,因为onLoad生命周期组件可能尚未创建完毕
  168. onReady() {
  169. this.$refs.uForm.setRules(this.rules);
  170. },
  171. methods: {
  172. customerName(value) {
  173. var userInfo = this.$cache.getCache('userInfo')
  174. if (userInfo.userType == 'customer') {
  175. if (value.field != 'customerName') {
  176. if (value.type == 'input') {
  177. return true
  178. }
  179. }
  180. } else {
  181. if (value.type == 'input') {
  182. return true
  183. }
  184. }
  185. },
  186. change(e) {
  187. this.columns = []
  188. this.fieldType = e.field
  189. this.show = true
  190. this.$nextTick(() => {
  191. this.columns.push(e.options)
  192. })
  193. },
  194. // 选择弹窗滚动
  195. changeil(value) {
  196. if (value.field == "status") {
  197. this.columns = []
  198. this.fieldType = value.field
  199. this.show = true
  200. this.$nextTick(() => {
  201. this.columns.push(value.options)
  202. })
  203. } else if (value.field == "freezeClaim") {
  204. this.freezeList = value.options
  205. this.freezeList.forEach(item => {
  206. item.flag = false
  207. })
  208. this.model.freezeClaim.forEach(event => {
  209. this.freezeList.filter(item1 => {
  210. if (item1.value == event) {
  211. item1.flag = true
  212. }
  213. })
  214. })
  215. this.freezeShow = true
  216. this.getSelected()
  217. } else {
  218. this.$emit('selector', value)
  219. }
  220. },
  221. // 选择确定
  222. confirm(value, type) {
  223. this.show = false
  224. this.model[type] = value.value[0].label
  225. },
  226. // 点击确定
  227. cancel() {
  228. this.show = false
  229. },
  230. findIndex(code, list) {
  231. if (!code || !list) {
  232. return [0]
  233. }
  234. return [list.findIndex((item) => (item.label === code || item.label === code))]
  235. },
  236. // 新增图片
  237. async afterRead(event, each) {
  238. this.list.forEach(async item1 => {
  239. if (item1.field == each.field) {
  240. // item1.fileList1 = this.fileList1
  241. // 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
  242. let lists = [].concat(event.file)
  243. let fileListLen = item1.fileList1.length
  244. lists.map((item) => {
  245. item1.fileList1.push({
  246. ...item,
  247. status: 'uploading',
  248. message: '上传中'
  249. })
  250. })
  251. uni.showLoading({
  252. title: '上传中',
  253. mask: true,
  254. })
  255. for (let i = 0; i < lists.length; i++) {
  256. const result = await this.uploadFilePromise(lists[i].url)
  257. let item = item1.fileList1[fileListLen]
  258. item1.fileList1.splice(fileListLen, 1, Object.assign(item, {
  259. status: 'success',
  260. message: '',
  261. url: result
  262. }))
  263. fileListLen++
  264. }
  265. var arr = []
  266. item1.fileList1.forEach(item1 => {
  267. arr.push(item1.url)
  268. })
  269. uni.hideLoading();
  270. if (each.field == 'prescription') {
  271. this.model[each.field] = arr
  272. this.$refs.uForm.validateField(each.field)
  273. } else {
  274. this.model[each.field] = arr.join()
  275. this.$refs.uForm.validateField(each.field)
  276. }
  277. }
  278. })
  279. },
  280. // 删除图片
  281. deletePic(event, each) {
  282. this.list.forEach(async item1 => {
  283. if (item1.field == each.field) {
  284. item1.fileList1.splice(event.index, 1)
  285. var arr = []
  286. item1.fileList1.forEach(item1 => {
  287. arr.push(item1.url)
  288. })
  289. uni.hideLoading();
  290. if (each.field == 'prescription') {
  291. this.model[each.field] = arr
  292. } else {
  293. this.model[each.field] = arr.join()
  294. }
  295. }
  296. })
  297. },
  298. uploadFilePromise(url) {
  299. return new Promise((resolve, reject) => {
  300. let a = uni.uploadFile({
  301. url: ENV.APP_DEV_URL + '/api/upload', // 仅为示例,非真实的接口地址
  302. filePath: url,
  303. name: 'file',
  304. // formData: {
  305. // user: 'test'
  306. // },
  307. header: {
  308. 'Authorization': 'Bearer ' + uni.getStorageSync('access_token'),
  309. },
  310. success: (res) => {
  311. let state = JSON.parse(res.data)
  312. setTimeout(() => {
  313. if (state.code == 200) {
  314. resolve(state.data)
  315. }
  316. }, 100)
  317. }
  318. });
  319. })
  320. },
  321. // 扫一扫
  322. sweep(field, flag) {
  323. if (flag) {
  324. if (!this.addloading) {
  325. this.$emit('getSweep', this.model[field])
  326. }
  327. } else {
  328. // 允许从相机和相册扫码
  329. uni.scanCode({
  330. scanType: ['barCode', 'qrCode'],
  331. autoZoom: false,
  332. success: (res) => {
  333. if (res.result) {
  334. let url = res.result;
  335. this.$emit('getSweep', url)
  336. this.model[field] = url
  337. } else {
  338. console.log('请重新扫描');
  339. return false;
  340. }
  341. },
  342. fail: (res) => {
  343. console.log('未识别到二维码1');
  344. }
  345. })
  346. }
  347. },
  348. //子组件校验,传递到父组件
  349. async validateForm() {
  350. let flag = null
  351. await this.$refs.uForm.validate(valid => {}).then(res => {
  352. flag = true
  353. }).catch(err => {
  354. flag = false
  355. })
  356. return flag
  357. },
  358. // 选择冷冻时间
  359. freezeSelect(event) {
  360. this.freezeList.forEach(item => {
  361. if (item.value == event.value) {
  362. if (item.flag) {
  363. item.flag = false
  364. } else {
  365. item.flag = true
  366. }
  367. }
  368. })
  369. this.getSelected()
  370. this.$forceUpdate()
  371. },
  372. // 获取已选
  373. getSelected() {
  374. var arr = []
  375. this.freezeList.forEach(item => {
  376. if (item.flag) {
  377. arr.push(item.value)
  378. }
  379. })
  380. this.selectedData = arr
  381. },
  382. // 获取选择名称
  383. getTagName(event) {
  384. let name
  385. this.freezeList.forEach(item => {
  386. if (event == item.value) {
  387. name = item.label
  388. }
  389. })
  390. return name
  391. },
  392. // 数组展示
  393. getTimeName(event) {
  394. var arr = event.join(' , ')
  395. return arr
  396. },
  397. // 删除选择项
  398. closeFreeze(event) {
  399. this.freezeList.forEach(item => {
  400. if (item.value == event) {
  401. item.flag = false
  402. }
  403. })
  404. this.selectedData = this.selectedData.filter(item => item !== event);
  405. },
  406. // 单个表单验证
  407. formValidation(event) {
  408. this.$refs['uForm'].validateField(event)
  409. },
  410. // 取消
  411. freezeCancel() {
  412. this.freezeShow = false
  413. },
  414. // 确定
  415. freezeConfirm() {
  416. this.model.freezeClaim = this.selectedData
  417. this.freezeShow = false
  418. },
  419. close() {
  420. this.freezeShow = false
  421. }
  422. },
  423. }
  424. </script>
  425. <style lang="scss">
  426. .card_form_item {
  427. display: flex;
  428. width: 100%;
  429. }
  430. .card_sweep {
  431. display: flex;
  432. flex-direction: column;
  433. justify-content: center;
  434. align-items: center;
  435. height: 70rpx;
  436. border: 1rpx solid #e5e5e5;
  437. border-radius: 8rpx;
  438. margin-left: 10rpx;
  439. span {
  440. margin: 0rpx 10rpx;
  441. display: flex;
  442. font-size: 22rpx;
  443. }
  444. }
  445. .card_search_gray {
  446. display: flex;
  447. flex-direction: row;
  448. align-items: center;
  449. justify-content: space-between;
  450. flex: 1;
  451. padding: 12rpx 18rpx;
  452. border-radius: 8rpx;
  453. line-height: 48rpx;
  454. }
  455. .title_gray {
  456. font-size: 30rpx;
  457. color: #c8c9cc;
  458. }
  459. .gray_font {
  460. color: #c8c9cc;
  461. }
  462. .blue_font {
  463. color: #3c9cff;
  464. }
  465. // 伪元素1rpx边框
  466. .frame {
  467. position: relative; //重要
  468. }
  469. .frame::after {
  470. position: absolute;
  471. content: '';
  472. border: 2rpx solid #e7e6e4;
  473. border-radius: 16rpx;
  474. width: 200%;
  475. height: 200%;
  476. top: 0;
  477. left: 0;
  478. transform: scale(0.5);
  479. transform-origin: 0 0;
  480. pointer-events: none;
  481. /* 使伪元素不会阻止鼠标事件 */
  482. }
  483. .card_drug_list {
  484. border-radius: 10rpx;
  485. border-top: 1px solid #f4f4f5;
  486. // box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, .12),
  487. }
  488. .tittle_freeze {
  489. padding: 0px 30rpx;
  490. }
  491. .freeze_content {
  492. position: relative;
  493. padding: 100rpx 0rpx;
  494. }
  495. .card_selected_list {
  496. position: absolute;
  497. top: 20rpx;
  498. left: 0;
  499. right: 0;
  500. border-bottom: 1rpx solid #f4f4f5;
  501. display: flex;
  502. align-items: center;
  503. justify-content: center;
  504. padding-bottom: 20rpx;
  505. }
  506. .hint_freeze {
  507. color: #909399;
  508. font-size: 30rpx;
  509. }
  510. .fontsize_freeze {
  511. display: flex;
  512. align-items: center;
  513. justify-content: space-between;
  514. padding: 20rpx 30rpx;
  515. height: 50rpx;
  516. }
  517. .add_card {
  518. margin-left: 10rpx;
  519. width: 40rpx;
  520. height: 46rpx;
  521. border-radius: 8rpx;
  522. padding: 6px 9px;
  523. border: 1px solid #dadbde;
  524. }
  525. .add_cardil {
  526. display: flex;
  527. margin-left: 10rpx;
  528. }
  529. </style>