seiminModel.vue 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <!--
  2. * @Author: 廖明明
  3. * @Date: 2022-04-01 17:11:19
  4. * @LastEditors: 廖明明
  5. * @LastEditTime: 2022-04-02 17:03:14
  6. * @Description: 自定义弹窗组件
  7. -->
  8. <template>
  9. <view class="seiminModel seiminModel_mask" v-if="opts.isVisible">
  10. <view class="seiminModel_container animate__animated animate__fadeIn animate__faster">
  11. <!-- 标题 -->
  12. <view class="seiminModel_header">
  13. <text>{{ opts.title }}</text>
  14. <text class="seiminModel_countDown" v-if="nurseDeptSwitchTip < 0 || (nurseDeptSwitchTip > 0 && closeTime > 0)">
  15. <text v-if="nurseDeptSwitchTip < 0">关闭</text>倒计时<text>{{ closeTime }}s</text>
  16. </text>
  17. </view>
  18. <!-- 动态二维码 -->
  19. <view class="seiminModel_content qrcode" v-if="opts.skin === 'qrcode'">
  20. <image class="w100" :src="nurseCodeImg" mode="widthFix"></image>
  21. <view class="qrcode_operate">
  22. <view class="refreshQRCode" @click="showNurseCode">
  23. 刷新
  24. </view>
  25. <view>{{ refreshQRCodeTime }}s</view>
  26. </view>
  27. </view>
  28. <!-- 正常弹窗 -->
  29. <view class="seiminModel_content" v-else>
  30. <!-- 图标 -->
  31. <view class="seiminModel_status">
  32. <text class="pda pda-shibai red" v-if="opts.icon === 'error'"></text>
  33. <text class="pda pda-duigou green" v-if="opts.icon === 'success'"></text>
  34. </view>
  35. <!-- 内容 -->
  36. <view class="seiminModel_txt" v-html="opts.content"></view>
  37. </view>
  38. <!-- 底部 -->
  39. <view class="seiminModel_footer" v-if="nurseDeptSwitchTip <= 0 || (nurseDeptSwitchTip > 0 && closeTime === 0)">
  40. <view class="seiminModel_footer__btn" v-for="(btn, i) in opts.btns" :style="{
  41. flex: btn.flex,
  42. color: btn.textColor,
  43. }" @click="btn.click($event)" :key="i">{{ btn.name }}</view>
  44. </view>
  45. </view>
  46. </view>
  47. </template>
  48. <script>
  49. import {
  50. mapState
  51. } from 'vuex';
  52. import {
  53. reqDeptCodes
  54. } from '../../request/api.js';
  55. export default {
  56. name: "seiminModel",
  57. data() {
  58. return {
  59. // 配置项
  60. opts: {},
  61. // 动态二维码定时器
  62. timer: null,
  63. // 动态二维码qrcode
  64. nurseCodeImg: '',
  65. // 动态二维码刷新间隔时长
  66. refreshQRCodeTime: 30,
  67. // 护士科室切换提示自动关闭设置(时长,单位秒)
  68. closeTime: 0,
  69. // 护士科室切换提示自动关闭设置(定时器,单位秒)
  70. timerCloseTime: null,
  71. };
  72. },
  73. computed: {
  74. ...mapState(['nurseDeptSwitchTip']),
  75. ...mapState('user', ['loginInfo']),
  76. },
  77. methods: {
  78. // 显示弹窗
  79. show(args = {}) {
  80. // 默认配置项
  81. let defaultOptions = {
  82. skin: "default", //弹窗风格(default|toast|qrcode|)
  83. isVisible: false, //是否显示弹窗
  84. title: "提示", //标题
  85. icon:'success',//图标(success|error|)
  86. content: "", //内容
  87. btns: [{
  88. name: "取消",
  89. textColor: "#666",
  90. flex: 1,
  91. click: this.close
  92. },
  93. {
  94. name: "确定",
  95. textColor: "#666",
  96. flex: 1,
  97. click: this.close
  98. },
  99. ], //弹窗按钮
  100. };
  101. // 根据弹窗风格修改默认配置项
  102. switch (args.skin) {
  103. case "toast":
  104. defaultOptions.btns = [{
  105. name: "知道了",
  106. textColor: "#49b856",
  107. flex: 1,
  108. click: this.close,
  109. }, ];
  110. break;
  111. }
  112. // 按钮合并参数
  113. if (Array.isArray(args.btns)) {
  114. let btns = [];
  115. args.btns.forEach((v, i) => {
  116. btns.push(Object.assign({}, defaultOptions.btns[i], v));
  117. })
  118. args.btns = btns;
  119. }
  120. // 合并配置
  121. this.opts = Object.assign({}, defaultOptions, args, {
  122. isVisible: true,
  123. });
  124. // 如果是动态二维码,则需要发起请求
  125. if (this.opts.skin === 'qrcode') {
  126. this.showNurseCode();
  127. }
  128. },
  129. // 关闭弹窗
  130. close() {
  131. this.opts.isVisible = false;
  132. if (this.opts.skin === 'qrcode') {
  133. clearInterval(this.timer);
  134. this.timer = null;
  135. }
  136. },
  137. // 科室动态二维码方法
  138. showNurseCode() {
  139. let deptId = this.loginInfo.user && this.loginInfo.user.dept.id;
  140. reqDeptCodes([deptId]).then(res => {
  141. if (res.status == 200) {
  142. this.nurseCodeImg = res["data"][0].base64;
  143. this.refreshQRCodeTime = res["data"][0].refreshQRCodeTime;
  144. clearInterval(this.timer);
  145. this.timer = setInterval(() => {
  146. this.refreshQRCodeTime = Math.max(--this.refreshQRCodeTime, 0);
  147. if (this.refreshQRCodeTime === 0) {
  148. clearInterval(this.timer);
  149. this.showNurseCode();
  150. }
  151. }, 1000);
  152. }
  153. })
  154. },
  155. // 切换科室弹窗
  156. showChangeDept(options = {}) {
  157. this.show(options);
  158. // (1) 当用户设置为正数时,用户必须查看此窗体指定秒数。
  159. // (2) 当用户设置为负数时,用户可点击知道了也可倒计时自动关闭。
  160. // (3) 如果用户填写0则为无自动关闭和强制查看时间。
  161. if (this.nurseDeptSwitchTip === 0) {
  162. return;
  163. }
  164. this.closeTime = Math.abs(this.nurseDeptSwitchTip);
  165. clearInterval(this.timerCloseTime);
  166. this.timerCloseTime = setInterval(() => {
  167. this.closeTime = Math.max(--this.closeTime, 0);
  168. if (this.closeTime === 0) {
  169. if (this.nurseDeptSwitchTip < 0) {
  170. this.close();
  171. }
  172. clearInterval(this.timerCloseTime);
  173. }
  174. }, 1000);
  175. }
  176. }
  177. };
  178. </script>
  179. <style lang="scss" scoped>
  180. .seiminModel {
  181. font-size: 36rpx;
  182. color: #000;
  183. line-height: 50rpx;
  184. text-align: center;
  185. &.seiminModel_mask {
  186. background-color: rgba(0, 0, 0, 0.5);
  187. position: fixed;
  188. top: 0;
  189. right: 0;
  190. bottom: 0;
  191. left: 0;
  192. margin: auto;
  193. z-index: 9999;
  194. @include flex(center, center);
  195. .seiminModel_container {
  196. width: 560rpx;
  197. border-radius: 8rpx;
  198. background-color: #fff;
  199. display: flex;
  200. flex-direction: column;
  201. align-content: center;
  202. .seiminModel_status {
  203. margin-bottom: 35rpx;
  204. .pda {
  205. font-size: 138rpx;
  206. }
  207. }
  208. .seiminModel_header {
  209. height: 100rpx;
  210. position: relative;
  211. @include flex(center, center);
  212. .seiminModel_countDown {
  213. position: absolute;
  214. right: 26rpx;
  215. font-size: 28rpx;
  216. color: $defaultColor;
  217. }
  218. }
  219. .seiminModel_content {
  220. flex: 1;
  221. background-color: #f9fafb;
  222. margin: 0 36rpx 25rpx;
  223. border: 1px solid #e5e9ed;
  224. color: #333;
  225. padding: 76rpx 24rpx;
  226. @include numbersAndLettersNoWrap;
  227. &.qrcode {
  228. padding: 24rpx;
  229. font-size: 32rpx;
  230. color: #999;
  231. .qrcode_operate {
  232. @include flex(space-between, center);
  233. .refreshQRCode {
  234. color: $defaultColor;
  235. }
  236. }
  237. }
  238. .red {
  239. color: $textColorRed;
  240. }
  241. .green {
  242. color: $defaultColor;
  243. }
  244. }
  245. .seiminModel_footer {
  246. border-top: 1px solid #e5e5e5;
  247. height: 100rpx;
  248. color: #666;
  249. @include flex(center, center);
  250. .seiminModel_footer__btn {
  251. height: 100%;
  252. @include flex(center, center);
  253. position: relative;
  254. &::after {
  255. content: "";
  256. height: 86rpx;
  257. position: absolute;
  258. width: 1px;
  259. bottom: 0;
  260. right: 0;
  261. background-color: #dde1e5;
  262. }
  263. }
  264. }
  265. }
  266. }
  267. }
  268. </style>