seiminModel.vue 8.2 KB

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