index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  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.title" @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">
  17. <view class="name">{{item.title||'暂无标题'}}</view>
  18. <view class="other textOver">
  19. 来源:{{item.origin||'暂无'}}
  20. </view>
  21. <view class="other textOver">
  22. 创建时间:{{item.create_time||'暂无'}}
  23. </view>
  24. <view class="other textOver">
  25. 是否启用:{{item.is_use == '0' ? '是' : '否'}}
  26. </view>
  27. <view class="button">
  28. <button class="warning" size="mini" type="warn" @tap.stop="toEdit(item)">修改</button>
  29. <button class="danger" size="mini" type="warn" @tap.stop="toDel(item)">删除</button>
  30. </view>
  31. </view>
  32. </view>
  33. <view class="is_bottom" v-if="is_bottom">
  34. <text>{{config.bottom_title||'到底了!'}}</text>
  35. </view>
  36. </scroll-view>
  37. </view>
  38. <!-- 修改/添加信息 -->
  39. <uni-popup ref="popup" background-color="#fff" type="center" :is-mask-click="false" @change="change">
  40. <view class="popup">
  41. <view class="close">
  42. <text>信息管理</text>
  43. <uni-icons @tap="toClose" type="close" size="20"></uni-icons>
  44. </view>
  45. <view class="info">
  46. <scroll-view class="scroll-view" scroll-y="true">
  47. <view class="list-scroll-view">
  48. <view class="info_1">
  49. <uni-forms ref="valiForm" :rules="rules" :modelValue="form" label-width="85">
  50. <uni-forms-item label="标题" required name="title">
  51. <uni-easyinput v-model="form.title" placeholder="请输入标题" />
  52. </uni-forms-item>
  53. <uni-forms-item label="来源" required name="origin">
  54. <uni-easyinput v-model="form.origin" placeholder="请输入来源" />
  55. </uni-forms-item>
  56. <uni-forms-item label="封面图片" required name="img_url">
  57. <upload class='upload' :list="form.img_url" name="img_url" :count="1"
  58. @uplSuc="uplSuc" @uplDel="uplDel">
  59. </upload>
  60. </uni-forms-item>
  61. <uni-forms-item label="内容" required name="content">
  62. <editor style="width: 100%; padding: 10upx;" id="editor"
  63. :placeholder="placeholder" @input="editorChange" @ready="onEditorReady">
  64. </editor>
  65. </uni-forms-item>
  66. <uni-forms-item label="是否启用" name="is_use">
  67. <uni-data-select v-model="form.is_use" :localdata="is_useList"
  68. @change="is_usechange">
  69. </uni-data-select>
  70. </uni-forms-item>
  71. </uni-forms>
  72. <button class="button" size="mini" type="primary"
  73. @click="submit('valiForm')">保存</button>
  74. </view>
  75. </view>
  76. </scroll-view>
  77. </view>
  78. </view>
  79. </uni-popup>
  80. </view>
  81. </template>
  82. <script>
  83. import upload from '../../components/upload/index.vue';
  84. export default {
  85. components: {
  86. upload
  87. },
  88. data() {
  89. return {
  90. user: {},
  91. config: {},
  92. searchInfo: {},
  93. list: [],
  94. total: 0,
  95. skip: 0,
  96. limit: 10,
  97. page: 0,
  98. form: {
  99. img_url: []
  100. },
  101. // 校验规则
  102. rules: {
  103. title: {
  104. rules: [{
  105. required: true,
  106. errorMessage: '标题不能为空'
  107. }]
  108. },
  109. origin: {
  110. rules: [{
  111. required: true,
  112. errorMessage: '来源不能为空'
  113. }]
  114. },
  115. img_url: {
  116. rules: [{
  117. required: true,
  118. errorMessage: '请上传封面图片'
  119. }]
  120. },
  121. },
  122. is_useList: [{
  123. text: '是',
  124. value: '0'
  125. },
  126. {
  127. text: '否',
  128. value: '1'
  129. }
  130. ],
  131. placeholder: '请输入内容',
  132. content: '',
  133. // 数据是否触底
  134. is_bottom: false,
  135. scrollTop: 0,
  136. // 禁止滚动穿透
  137. show: false
  138. }
  139. },
  140. onShow: async function() {
  141. const that = this;
  142. that.clearPage();
  143. await that.searchToken();
  144. await that.searchConfig();
  145. await that.search();
  146. },
  147. onPullDownRefresh: async function() {
  148. const that = this;
  149. that.clearPage();
  150. await that.search();
  151. uni.stopPullDownRefresh();
  152. },
  153. methods: {
  154. // 禁止滚动穿透
  155. change(e) {
  156. const that = this;
  157. that.show = e.show
  158. },
  159. searchToken() {
  160. const that = this;
  161. try {
  162. const res = uni.getStorageSync('token');
  163. if (res) {
  164. const user = that.$jwt(res);
  165. that.$set(that, `user`, user);
  166. }
  167. } catch (e) {}
  168. },
  169. searchConfig() {
  170. const that = this;
  171. try {
  172. const res = uni.getStorageSync('config');
  173. if (res) that.$set(that, `config`, res);
  174. } catch (e) {}
  175. },
  176. async search() {
  177. const that = this;
  178. let user = that.user;
  179. let info = {
  180. skip: that.skip,
  181. limit: that.limit,
  182. }
  183. if (that.user.role == 'Doctor') info.doctor = that.user._id
  184. else info.doctor = that.user.doctor
  185. const res = await that.$api(`/article`, 'GET', {
  186. ...info,
  187. ...that.searchInfo
  188. })
  189. if (res.errcode == '0') {
  190. let list = [...that.list, ...res.data];
  191. that.$set(that, `list`, list)
  192. that.$set(that, `total`, res.total)
  193. } else {
  194. uni.showToast({
  195. title: res.errmsg,
  196. });
  197. }
  198. },
  199. // 输入框
  200. toInput(e) {
  201. const that = this;
  202. if (that.searchInfo.title) that.$set(that.searchInfo, `title`, e.detail.value)
  203. else that.$set(that, `searchInfo`, {})
  204. that.clearPage();
  205. that.search();
  206. },
  207. // 是否使用
  208. is_usechange(is_use) {
  209. const that = this;
  210. that.$set(that.form, `is_use`, is_use);
  211. },
  212. // 富文本
  213. onEditorReady() {
  214. const that = this
  215. uni.createSelectorQuery().select('#editor').context((res) => {
  216. that.editorCtx = res.context
  217. that.editorCtx.setContents({
  218. html: that.form.content || '',
  219. success: (res) => {
  220. // console.log(res)
  221. },
  222. fail: (res) => {
  223. // console.log(res)
  224. },
  225. })
  226. }).exec()
  227. },
  228. editorChange: function(e) {
  229. const that = this
  230. that.$set(that, `content`, e.detail.html || '')
  231. },
  232. // 图片上传
  233. uplSuc(e) {
  234. const that = this;
  235. that.$set(that.form, `${e.name}`, [...that.form[e.name], e.data]);
  236. },
  237. // 图片删除
  238. uplDel(e) {
  239. const that = this;
  240. let data = that.form[e.name];
  241. let arr = data.filter((i, index) => index != e.data.index);
  242. that.$set(that.form, `${e.name}`, arr)
  243. },
  244. // 添加
  245. toAdd() {
  246. const that = this;
  247. that.$refs.popup.open()
  248. },
  249. // 修改
  250. async toEdit(item) {
  251. const that = this;
  252. const res = await that.$api(`/article/${item._id}`, 'GET', {})
  253. if (res.errcode == '0') {
  254. that.$set(that, `form`, res.data)
  255. that.onEditorReady()
  256. that.$refs.popup.open()
  257. } else {
  258. uni.showToast({
  259. title: res.errmsg,
  260. icon: 'none'
  261. });
  262. }
  263. },
  264. // 保存
  265. submit(ref) {
  266. const that = this;
  267. const form = that.form;
  268. that.$refs[ref].validate().then(async data => {
  269. let res;
  270. if (that.user.role == 'Doctor') data.doctor = that.user._id
  271. else data.doctor = that.user.doctor
  272. data.content = that.content
  273. if (form._id) res = await that.$api(`/article/${form._id}`, 'POST', data)
  274. else res = await that.$api(`/article`, 'POST', data)
  275. if (res.errcode == '0') {
  276. uni.showToast({
  277. title: '维护信息成功',
  278. icon: 'none'
  279. })
  280. that.toClose();
  281. that.clearPage();
  282. that.search();
  283. } else {
  284. uni.showToast({
  285. title: res.errmsg,
  286. icon: 'none'
  287. });
  288. }
  289. })
  290. },
  291. // 删除
  292. async toDel(item) {
  293. const that = this;
  294. uni.showModal({
  295. title: '提示',
  296. content: '您确定删除该数据吗?',
  297. success: async function(res) {
  298. if (res.confirm) {
  299. const res = await that.$api(`/article/${item._id||item.id}`, 'DELETE', {})
  300. if (res.errcode == 0) {
  301. that.clearPage();
  302. that.search();
  303. } else {
  304. uni.showToast({
  305. title: res.errmsg,
  306. icon: 'none'
  307. })
  308. }
  309. }
  310. }
  311. });
  312. },
  313. // 关闭弹框
  314. toClose() {
  315. const that = this;
  316. that.$set(that, `form`, {})
  317. that.onEditorReady()
  318. that.$refs.popup.close();
  319. },
  320. // 分页
  321. toPage(e) {
  322. const that = this;
  323. let list = that.list;
  324. let limit = that.limit;
  325. if (that.total > list.length) {
  326. uni.showLoading({
  327. title: '加载中',
  328. mask: true
  329. })
  330. let page = that.page + 1;
  331. that.$set(that, `page`, page)
  332. let skip = page * limit;
  333. that.$set(that, `skip`, skip)
  334. that.search();
  335. uni.hideLoading();
  336. } else that.$set(that, `is_bottom`, true)
  337. },
  338. toScroll(e) {
  339. const that = this;
  340. let up = that.scrollTop;
  341. that.$set(that, `scrollTop`, e.detail.scrollTop);
  342. let num = Math.sign(up - e.detail.scrollTop);
  343. if (num == 1) that.$set(that, `is_bottom`, false);
  344. },
  345. // 清空列表
  346. clearPage() {
  347. const that = this;
  348. that.$set(that, `list`, [])
  349. that.$set(that, `skip`, 0)
  350. that.$set(that, `limit`, 10)
  351. that.$set(that, `page`, 0)
  352. }
  353. }
  354. }
  355. </script>
  356. <style lang="scss" scoped>
  357. .main {
  358. display: flex;
  359. flex-direction: column;
  360. width: 100vw;
  361. height: 100vh;
  362. .one {
  363. display: flex;
  364. justify-content: center;
  365. align-items: center;
  366. padding: 2vw;
  367. .one_1 {
  368. padding: 0 2vw;
  369. width: 75vw;
  370. input {
  371. padding: 2vw;
  372. background-color: var(--f1Color);
  373. font-size: var(--font14Size);
  374. border-radius: 5px;
  375. }
  376. }
  377. .one_2 {
  378. padding: 2vw 0;
  379. .button {
  380. background-color: var(--f3CColor);
  381. color: var(--mainColor);
  382. }
  383. }
  384. }
  385. .two {
  386. position: relative;
  387. flex-grow: 1;
  388. background-color: var(--f9Color);
  389. .list:first-child {
  390. margin: 2vw;
  391. }
  392. .list {
  393. background-color: var(--mainColor);
  394. border: 1px solid var(--f5Color);
  395. padding: 2vw;
  396. margin: 0 2vw 2vw 2vw;
  397. border-radius: 5px;
  398. .name {
  399. font-size: var(--font14Size);
  400. font-weight: bold;
  401. padding: 2vw 0;
  402. }
  403. .other {
  404. font-size: var(--font12Size);
  405. color: var(--f85Color);
  406. }
  407. .button {
  408. margin: 2vw 0 0 0;
  409. text-align: center;
  410. .warning {
  411. background: var(--f3CColor);
  412. }
  413. .danger {
  414. background: var(--fF0Color);
  415. }
  416. button {
  417. margin: 0 1vw 0 0;
  418. }
  419. }
  420. }
  421. }
  422. .uni-popup {
  423. z-index: 9999 !important;
  424. }
  425. .popup {
  426. display: flex;
  427. flex-direction: column;
  428. width: 90vw;
  429. background-color: var(--f9Color);
  430. .close {
  431. display: flex;
  432. justify-content: space-between;
  433. padding: 2vw;
  434. text:first-child {
  435. font-size: var(--font16Size);
  436. font-weight: bold;
  437. }
  438. }
  439. .info {
  440. position: relative;
  441. height: 40vh;
  442. .info_1 {
  443. display: flex;
  444. flex-direction: column;
  445. padding: 2vw;
  446. #editor {
  447. width: 100%;
  448. height: 100px;
  449. border: 1px solid #F0F0F0;
  450. }
  451. .button {
  452. margin: 2vw 0 0 0;
  453. background-color: var(--f3CColor);
  454. color: var(--mainColor);
  455. font-size: var(--font14Size);
  456. }
  457. }
  458. }
  459. }
  460. }
  461. .scroll-view {
  462. position: absolute;
  463. top: 0;
  464. left: 0;
  465. right: 0;
  466. bottom: 0;
  467. .list-scroll-view {
  468. display: flex;
  469. flex-direction: column;
  470. }
  471. }
  472. .is_bottom {
  473. width: 100%;
  474. text-align: center;
  475. text {
  476. padding: 2vw 0;
  477. display: inline-block;
  478. color: var(--f85Color);
  479. font-size: var(--font14Size);
  480. }
  481. }
  482. </style>