index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. <template>
  2. <!-- 禁止滚动穿透 -->
  3. <page-meta :page-style="'overflow:'+(show?'hidden':'visible')"></page-meta>
  4. <view class="main">
  5. <view class="one">
  6. <view class="one_1">
  7. <input type="text" v-model="searchInfo.name" @input="toInput" placeholder="搜索群组名称">
  8. </view>
  9. <view class="one_2">
  10. <button size="mini" class="button" type="primary" @click="toAdd">添加</button>
  11. </view>
  12. </view>
  13. <view class="two">
  14. <scroll-view scroll-y="true" class="scroll-view" @scrolltolower="toPage" @scroll="toScroll">
  15. <view class="list-scroll-view">
  16. <view class="list" v-for="(item, index) in list" :key="index" @tap="toInfo(item)">
  17. <view class="name">{{item.name||'暂无群组名称'}}</view>
  18. <view class="other textOver">
  19. 简介:{{item.content||'暂无'}}
  20. </view>
  21. <view class="button">
  22. <button class="warning" size="mini" type="warn" @tap.stop="toEdit(item)">修改</button>
  23. <button class="warning" size="mini" type="warn" @tap.stop="toCode(item)">二维码</button>
  24. <button class="warning" size="mini" type="warn" @tap.stop="toPerson(item)">成员</button>
  25. <button class="danger" size="mini" type="warn" @tap.stop="toDel(item)">删除</button>
  26. </view>
  27. </view>
  28. </view>
  29. <view class="is_bottom" v-if="is_bottom">
  30. <text>{{config.bottom_title||'到底了!'}}</text>
  31. </view>
  32. </scroll-view>
  33. </view>
  34. <!-- 修改/添加信息 -->
  35. <uni-popup ref="popup" background-color="#fff" type="center" :is-mask-click="false" @change="change">
  36. <view class="popup">
  37. <view class="close">
  38. <text>信息管理</text>
  39. <uni-icons @tap="toClose" type="close" size="20"></uni-icons>
  40. </view>
  41. <view class="info_1">
  42. <uni-forms ref="valiForm" :rules="rules" :modelValue="form">
  43. <uni-forms-item label="群名" required name="name">
  44. <uni-easyinput v-model="form.name" placeholder="请输入群名" />
  45. </uni-forms-item>
  46. <uni-forms-item label="简介" required name="content">
  47. <uni-easyinput type="textarea" autoHeight v-model="form.content" placeholder="请输入简介" />
  48. </uni-forms-item>
  49. </uni-forms>
  50. <view class="bottom">
  51. <button class="button" size="mini" type="primary" @click="submit('valiForm')">保存</button>
  52. </view>
  53. </view>
  54. </view>
  55. </uni-popup>
  56. <uni-popup ref="code" background-color="#fff" type="center" :is-mask-click="false" @change="change">
  57. <view class="popup">
  58. <view class="close">
  59. <text>二维码</text>
  60. <uni-icons @tap="toClose" type="close" size="20"></uni-icons>
  61. </view>
  62. <view class="info_1">
  63. <view class="code">
  64. <canvas canvas-id="qrcode" ref="qrcode" style="width: 150px; height: 150px;" />
  65. </view>
  66. <view class="bottom">
  67. <button class="button" size="mini" type="primary" @tap="toSave">保存二维码</button>
  68. </view>
  69. </view>
  70. </view>
  71. </uni-popup>
  72. </view>
  73. </template>
  74. <script>
  75. import UQRCode from 'uqrcodejs';
  76. export default {
  77. data() {
  78. return {
  79. user: {},
  80. config: {},
  81. searchInfo: {},
  82. list: [],
  83. total: 0,
  84. skip: 0,
  85. limit: 10,
  86. page: 0,
  87. form: {},
  88. // 校验规则
  89. rules: {
  90. name: {
  91. rules: [{
  92. required: true,
  93. errorMessage: '群名不能为空'
  94. }]
  95. },
  96. content: {
  97. rules: [{
  98. required: true,
  99. errorMessage: '简介不能为空'
  100. }]
  101. }
  102. },
  103. // 数据是否触底
  104. is_bottom: false,
  105. scrollTop: 0,
  106. // 禁止滚动穿透
  107. show: false
  108. }
  109. },
  110. onShow: async function() {
  111. const that = this;
  112. that.clearPage();
  113. await that.searchToken();
  114. await that.searchConfig();
  115. await that.search();
  116. },
  117. onPullDownRefresh: async function() {
  118. const that = this;
  119. that.clearPage();
  120. await that.search();
  121. uni.stopPullDownRefresh();
  122. },
  123. methods: {
  124. // 禁止滚动穿透
  125. change(e) {
  126. const that = this;
  127. that.show = e.show
  128. },
  129. searchToken() {
  130. const that = this;
  131. try {
  132. const res = uni.getStorageSync('token');
  133. if (res) {
  134. const user = that.$jwt(res);
  135. that.$set(that, `user`, user);
  136. }
  137. } catch (e) {}
  138. },
  139. searchConfig() {
  140. const that = this;
  141. try {
  142. const res = uni.getStorageSync('config');
  143. if (res) that.$set(that, `config`, res);
  144. } catch (e) {}
  145. },
  146. async search() {
  147. const that = this;
  148. let user = that.user;
  149. let info = {
  150. skip: that.skip,
  151. limit: that.limit,
  152. }
  153. if (that.user.role == 'Doctor') info.doctor = that.user._id
  154. else info.doctor = that.user.doctor
  155. const res = await that.$api(`/group`, 'GET', {
  156. ...info,
  157. ...that.searchInfo
  158. })
  159. if (res.errcode == '0') {
  160. let list = [...that.list, ...res.data];
  161. that.$set(that, `list`, list)
  162. that.$set(that, `total`, res.total)
  163. } else {
  164. uni.showToast({
  165. title: res.errmsg,
  166. });
  167. }
  168. },
  169. // 输入框
  170. toInput(e) {
  171. const that = this;
  172. if (that.searchInfo.name) that.$set(that.searchInfo, `name`, e.detail.value)
  173. else that.$set(that, `searchInfo`, {})
  174. that.clearPage();
  175. that.search();
  176. },
  177. // 添加
  178. toAdd() {
  179. const that = this;
  180. that.$refs.popup.open()
  181. },
  182. // 二维码
  183. toCode(item) {
  184. const that = this;
  185. const serverFile = that.$config.serverFile;
  186. // 需要注意的是该方法的尺寸单位默认为px可以使用
  187. // 获取uQRCode实例
  188. var qr = new UQRCode();
  189. // 设置二维码内容
  190. qr.data = `${serverFile}/login?id=${item._id}&type=${'group'}`;
  191. // 设置二维码大小,必须与canvas设置的宽高一致
  192. qr.size = '150';
  193. // 指定二维码的边距
  194. qr.margin = '2';
  195. // 提升二维码美观度,如果关闭的话二维码中会有很明显的白色线条
  196. qr.useDynamicSize = true;
  197. // 调用制作二维码方法
  198. qr.make();
  199. // 获取canvas上下文
  200. var canvasContext = uni.createCanvasContext('qrcode', this); // 如果是组件,this必须传入
  201. // // 设置uQRCode实例的canvas上下文
  202. qr.canvasContext = canvasContext;
  203. // 调用绘制方法将二维码图案绘制到canvas上
  204. qr.drawCanvas();
  205. that.$refs.code.open()
  206. },
  207. // 保存二维码
  208. toSave() {
  209. setTimeout(() => { //在draw方法调用之后,为了避免出现异常,所以采用定时器
  210. uni.canvasToTempFilePath({ // 这里保存图片使用uniapp官方的方法,先获取文件临时路径
  211. canvasId: 'qrcode',
  212. width: '150',
  213. height: '150',
  214. success: res => {
  215. // 获取文件的临时路径之后结合saveImageToPhotosAlbu方法就可以把二维码保存到相册中
  216. uni.saveImageToPhotosAlbum({
  217. filePath: res.tempFilePath,
  218. success: res => {
  219. uni.showToast({
  220. title: '保存成功',
  221. icon: 'success'
  222. })
  223. },
  224. fail: err => {
  225. console.log(err);
  226. }
  227. })
  228. },
  229. fail: err => {
  230. console.log(err);
  231. }
  232. })
  233. }, 1000)
  234. },
  235. // 成员
  236. toPerson(item) {
  237. const that = this;
  238. uni.navigateTo({
  239. url: `/pagesMy/person/index?id=${item.id||item._id}`
  240. })
  241. },
  242. // 修改
  243. async toEdit(item) {
  244. const that = this;
  245. const res = await that.$api(`/group/${item._id}`, 'GET', {})
  246. if (res.errcode == '0') {
  247. that.$set(that, `form`, res.data)
  248. that.$refs.popup.open()
  249. } else {
  250. uni.showToast({
  251. title: res.errmsg,
  252. icon: 'none'
  253. });
  254. }
  255. },
  256. // 保存
  257. submit(ref) {
  258. const that = this;
  259. const form = that.form;
  260. that.$refs[ref].validate().then(async data => {
  261. let res;
  262. if (that.user.role == 'Doctor') data.doctor = that.user._id
  263. else data.doctor = that.user.doctor
  264. if (form._id) res = await that.$api(`/group/${form._id}`, 'POST', data)
  265. else res = await that.$api(`/group`, 'POST', data)
  266. if (res.errcode == '0') {
  267. that.toClose();
  268. that.clearPage();
  269. that.search();
  270. } else {
  271. uni.showToast({
  272. title: res.errmsg,
  273. icon: 'none'
  274. });
  275. }
  276. })
  277. },
  278. // 删除
  279. async toDel(item) {
  280. const that = this;
  281. uni.showModal({
  282. title: '提示',
  283. content: '您确定删除该数据吗?',
  284. success: async function(res) {
  285. if (res.confirm) {
  286. const res = await that.$api(`/group/${item._id||item.id}`, 'DELETE', {})
  287. if (res.errcode == 0) {
  288. that.clearPage();
  289. that.search();
  290. } else {
  291. uni.showToast({
  292. title: res.errmsg,
  293. icon: 'none'
  294. })
  295. }
  296. }
  297. }
  298. });
  299. },
  300. // 关闭弹框
  301. toClose() {
  302. const that = this;
  303. that.$set(that, `form`, {})
  304. that.$refs.popup.close();
  305. that.$refs.code.close();
  306. },
  307. // 详情
  308. toInfo(item) {
  309. uni.navigateTo({
  310. url: `/pagesHome/group/index?id=${item.id||item._id}&title=${item.name}`
  311. })
  312. },
  313. // 分页
  314. toPage(e) {
  315. const that = this;
  316. let list = that.list;
  317. let limit = that.limit;
  318. if (that.total > list.length) {
  319. uni.showLoading({
  320. title: '加载中',
  321. mask: true
  322. })
  323. let page = that.page + 1;
  324. that.$set(that, `page`, page)
  325. let skip = page * limit;
  326. that.$set(that, `skip`, skip)
  327. that.search();
  328. uni.hideLoading();
  329. } else that.$set(that, `is_bottom`, true)
  330. },
  331. toScroll(e) {
  332. const that = this;
  333. let up = that.scrollTop;
  334. that.$set(that, `scrollTop`, e.detail.scrollTop);
  335. let num = Math.sign(up - e.detail.scrollTop);
  336. if (num == 1) that.$set(that, `is_bottom`, false);
  337. },
  338. // 清空列表
  339. clearPage() {
  340. const that = this;
  341. that.$set(that, `list`, [])
  342. that.$set(that, `skip`, 0)
  343. that.$set(that, `limit`, 10)
  344. that.$set(that, `page`, 0)
  345. }
  346. }
  347. }
  348. </script>
  349. <style lang="scss" scoped>
  350. .main {
  351. display: flex;
  352. flex-direction: column;
  353. width: 100vw;
  354. height: 100vh;
  355. .one {
  356. display: flex;
  357. justify-content: center;
  358. align-items: center;
  359. padding: 2vw;
  360. .one_1 {
  361. padding: 0 2vw;
  362. width: 75vw;
  363. input {
  364. padding: 2vw;
  365. background-color: var(--f1Color);
  366. font-size: var(--font14Size);
  367. border-radius: 5px;
  368. }
  369. }
  370. .one_2 {
  371. padding: 2vw 0;
  372. .button {
  373. background-color: var(--f3CColor);
  374. color: var(--mainColor);
  375. }
  376. }
  377. }
  378. .two {
  379. position: relative;
  380. flex-grow: 1;
  381. background-color: var(--f9Color);
  382. .list:first-child {
  383. margin: 2vw;
  384. }
  385. .list {
  386. background-color: var(--mainColor);
  387. border: 1px solid var(--f5Color);
  388. padding: 2vw;
  389. margin: 0 2vw 2vw 2vw;
  390. border-radius: 5px;
  391. .name {
  392. font-size: var(--font14Size);
  393. font-weight: bold;
  394. padding: 2vw 0;
  395. }
  396. .other {
  397. font-size: var(--font12Size);
  398. color: var(--f85Color);
  399. }
  400. .button {
  401. margin: 2vw 0 0 0;
  402. text-align: center;
  403. .warning {
  404. background: var(--f3CColor);
  405. }
  406. .danger {
  407. background: var(--fF0Color);
  408. }
  409. button {
  410. margin: 0 1vw 0 0;
  411. }
  412. }
  413. }
  414. }
  415. .uni-popup {
  416. z-index: 9999 !important;
  417. }
  418. .popup {
  419. display: flex;
  420. flex-direction: column;
  421. width: 90vw;
  422. background-color: var(--f9Color);
  423. .close {
  424. display: flex;
  425. justify-content: space-between;
  426. padding: 2vw;
  427. text:first-child {
  428. font-size: var(--font16Size);
  429. font-weight: bold;
  430. }
  431. }
  432. .info_1 {
  433. position: relative;
  434. display: flex;
  435. flex-direction: column;
  436. max-height: 40vh;
  437. padding: 2vw;
  438. .code {
  439. display: flex;
  440. flex-direction: column;
  441. align-items: center;
  442. }
  443. .bottom {
  444. text-align: center;
  445. .button {
  446. margin: 2vw 0 0 0;
  447. background-color: var(--f3CColor);
  448. color: var(--mainColor);
  449. font-size: var(--font14Size);
  450. }
  451. }
  452. }
  453. }
  454. }
  455. .scroll-view {
  456. position: absolute;
  457. top: 0;
  458. left: 0;
  459. right: 0;
  460. bottom: 0;
  461. .list-scroll-view {
  462. display: flex;
  463. flex-direction: column;
  464. }
  465. }
  466. .is_bottom {
  467. width: 100%;
  468. text-align: center;
  469. text {
  470. padding: 2vw 0;
  471. display: inline-block;
  472. color: var(--f85Color);
  473. font-size: var(--font14Size);
  474. }
  475. }
  476. </style>