App.vue 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098
  1. <script>
  2. import { mapGetters, mapActions } from 'vuex';
  3. import IMSDK, { IMMethods, MessageReceiveOptType, MessageType, SessionType } from 'openim-uniapp-polyfill';
  4. import { config } from '@/pages_im/common/config';
  5. import { getDbDir, Igexin, toastWithCallback } from '@/pages_im/util/common.js';
  6. import { conversationSort, secFormat, callingModule, meetingModule, parseMessageByType, prepareConversationState } from '@/pages_im/util/imCommon';
  7. import { PageEvents, UpdateMessageTypes, CustomType, ContactChooseTypes } from '@/pages_im/constant';
  8. import { openImLoginApi } from '@/pages_im/api/imBll';
  9. import NotificationUtil from '@/pages_im/util/notification';
  10. import newMessage from '@/pages_im/static/audio/newMessage.wav';
  11. import { getTlsSig,getDicts } from '@/api/common.js'
  12. import { checkLogin } from '@/api/user.js'
  13. let cacheConversationList = [];
  14. let updateDownloadTask = null;
  15. let notificationIntance = null;
  16. let pausing = false;
  17. let innerAudioContext;
  18. let notification;
  19. let uPushPlugin;
  20. export default {
  21. globalData: {
  22. wsUrl: '',
  23. appId: 'wx1e6d61497bba00ef'
  24. },
  25. onLaunch: function () {
  26. this.checkUpdate()
  27. this.initOpenIm();
  28. var that=this;
  29. uni.$on('refreshIM', () => {
  30. this.checkLogin();
  31. });
  32. var urls="https://17010831189.cdwjyyh.com;https://16946746017.cdwjyyh.com;https://13708196565.cdwjyyh.com;https://1700206673.cdwjyyh.com;https://17233317680.cdwjyyh.com;https://1700575323.cdwjyyh.com;https://17069749252.cdwjyyh.com;https://16973148962.cdwjyyh.com;https://1722131630.cdwjyyh.com;https://17146969562.cdwjyyh.com;https://1695072024.cdwjyyh.com;https://17203639647.cdwjyyh.com;https://16954404159.cdwjyyh.com;https://1707741400.cdwjyyh.com;https://17408937934.cdwjyyh.com;https://17180847536.cdwjyyh.com;https://17244394814.cdwjyyh.com;https://1703101076.cdwjyyh.com;https://17124251670.cdwjyyh.com;https://17017634981.cdwjyyh.com;https://1709430520.cdwjyyh.com;https://17163564434.cdwjyyh.com;https://17168038011.cdwjyyh.com;https://1710609621.cdwjyyh.com;https://1705257092.cdwjyyh.com;https://17211347588.cdwjyyh.com;https://17035647784.cdwjyyh.com;https://1721509816.cdwjyyh.com;https://1720396718.cdwjyyh.com;https://17214936263.cdwjyyh.com;https://1716050799.cdwjyyh.com;https://1713109810.cdwjyyh.com;https://172542243167.cdwjyyh.com;https://172240149208.cdwjyyh.com;https://1702848339.cdwjyyh.com;https://1707911907.cdwjyyh.com;https://1717849419.cdwjyyh.com;https://17038049724.cdwjyyh.com;https://1724650239.cdwjyyh.com;https://1707113459.cdwjyyh.com;https://1715669104.cdwjyyh.com;https://1710051545.cdwjyyh.com;https://1722269330.cdwjyyh.com;https://1710003925.cdwjyyh.com;https://17145545145.cdwjyyh.com;https://1720634288.cdwjyyh.com;https://1696593184.cdwjyyh.com;https://1704962208.cdwjyyh.com;https://1703146177.cdwjyyh.com;https://1704346325.cdwjyyh.com;https://1697387624.cdwjyyh.com;https://1702551094.cdwjyyh.com;https://1720523201.cdwjyyh.com;https://1714391651.cdwjyyh.com;https://16989457834.cdwjyyh.com;https://1710582715.cdwjyyh.com;https://1696073814.cdwjyyh.com;https://1701427000.cdwjyyh.com;https://1703620825.cdwjyyh.com;https://1716954881.cdwjyyh.com;https://1709258681.cdwjyyh.com;https://1702178349.cdwjyyh.com;https://1696037454.cdwjyyh.com;https://1707163288.cdwjyyh.com;https://1698272613.cdwjyyh.com;https://1695736399.cdwjyyh.com;https://1707979666.cdwjyyh.com;https://1699631662.cdwjyyh.com;https://1725584568.cdwjyyh.com;https://1709711499.cdwjyyh.com;https://1707988905.cdwjyyh.com;https://1709289861.cdwjyyh.com;https://1720027873.cdwjyyh.com;https://1723979172.cdwjyyh.com;https://1711804525.cdwjyyh.com;https://1702653210.cdwjyyh.com;https://1711075739.cdwjyyh.com;https://1710979987.cdwjyyh.com;https://1724292527.cdwjyyh.com;https://1704964596.cdwjyyh.com;https://1703840482.cdwjyyh.com;https://1709061808.cdwjyyh.com;https://1718492957.cdwjyyh.com;https://1708829102.cdwjyyh.com;https://1716362553.cdwjyyh.com;https://1710541443.cdwjyyh.com;https://1715811900.cdwjyyh.com;https://1718208786.cdwjyyh.com;https://1704651745.cdwjyyh.com;https://1699759405.cdwjyyh.com;https://1713080422.cdwjyyh.com;https://1715403843.cdwjyyh.com;https://1696900518.cdwjyyh.com;https://1707770189.cdwjyyh.com;https://1700034515.cdwjyyh.com;https://1715466167.cdwjyyh.com;https://1709976677.cdwjyyh.com;https://1712370330.cdwjyyh.com;https://1706087997.cdwjyyh.com;https://1703496196.cdwjyyh.com;https://17122663469.cdwjyyh.com;https://1712318592.cdwjyyh.com;https://1712812440.cdwjyyh.com;https://1715678161.cdwjyyh.com;https://1702028001.cdwjyyh.com;https://17216467850.cdwjyyh.com;https://1696462985.cdwjyyh.com;https://1707192149.cdwjyyh.com;https://17048421512.cdwjyyh.com;https://1723797034.cdwjyyh.com;https://1704429569.cdwjyyh.com;https://17092443255.cdwjyyh.com;https://1722028860.cdwjyyh.com;https://17129467809.cdwjyyh.com;https://1705848887.cdwjyyh.com;https://16945675535.cdwjyyh.com;https://17257464755.cdwjyyh.com;https://1723025937.cdwjyyh.com;https://17234848798.cdwjyyh.com;https://1700104177.cdwjyyh.com;https://17242943219.cdwjyyh.com;https://17262404998.cdwjyyh.com;https://17140341757.cdwjyyh.com;https://17134130421.cdwjyyh.com;https://1723148318.cdwjyyh.com;https://17257455505.cdwjyyh.com;https://17207640127.cdwjyyh.com;https://1709058929.cdwjyyh.com;https://17069353822.cdwjyyh.com;https://1698429582.cdwjyyh.com;https://17253124611.cdwjyyh.com;https://1709158760.cdwjyyh.com;https://17124964042.cdwjyyh.com;https://1707326074.cdwjyyh.com;https://17046524832.cdwjyyh.com;https://1722471447.cdwjyyh.com;https://1715081607.cdwjyyh.com;https://1722709008.cdwjyyh.com;https://1705411096.cdwjyyh.com;https://17221412356.cdwjyyh.com;https://173131762485.cdwjyyh.com;https://17106348388.cdwjyyh.com;https://1703201862.cdwjyyh.com;https://171645204084.cdwjyyh.com;https://17316201102.cdwjyyh.com;https://1714278120.cdwjyyh.com;https://169458141036.cdwjyyh.com;https://16966142587.cdwjyyh.com;https://1720738395.cdwjyyh.com;https://1722208363.cdwjyyh.com;https://169714438661.cdwjyyh.com;https://1717887413.cdwjyyh.com;https://1715113705.cdwjyyh.com;https://16960448580.cdwjyyh.com;https://16961466861.cdwjyyh.com;https://1707853597.cdwjyyh.com;https://1709274679.cdwjyyh.com;https://1722858089.cdwjyyh.com;https://1715419874.cdwjyyh.com;https://17151136007.cdwjyyh.com;https://1722314568.cdwjyyh.com;https://1724746541.cdwjyyh.com;https://1718762128.cdwjyyh.com;https://1720163684.cdwjyyh.com;https://17247470857.cdwjyyh.com;https://1708580403.cdwjyyh.com;https://1705948747.cdwjyyh.com;https://1700682425.cdwjyyh.com;https://170284458903.cdwjyyh.com;https://1725605169.cdwjyyh.com;https://16990645003.cdwjyyh.com;https://16946786637.cdwjyyh.com;https://17083564387.cdwjyyh.com;https://16994525562.cdwjyyh.com;https://1720968292.cdwjyyh.com;https://1710909698.cdwjyyh.com;https://1700467361.cdwjyyh.com;https://16953683561.cdwjyyh.com;https://17258458080.cdwjyyh.com;https://1702911871.cdwjyyh.com";
  33. var urlList=urls.split(";");
  34. console.log(this.getRandomInt(0,urlList.length-1))
  35. var path = urlList[this.getRandomInt(0,urlList.length-1)];
  36. //path="https://api.cdwjyyh.com";
  37. //path="https://test.userapp.his.cdwjyyh.com";
  38. uni.setStorageSync('requestPath',path)
  39. this.getDicts()
  40. },
  41. onUnload() {
  42. },
  43. onShow() {
  44. uni.getSystemInfo({
  45. success: (result) => {
  46. // 获取手机系统的状态栏高度(不同手机的状态栏高度不同)
  47. // console.log('当前手机的状态栏高度',result.statusBarHeight)
  48. let statusBarHeight = result.statusBarHeight + 'px'
  49. // 获取右侧胶囊的信息 单位px
  50. //#ifndef H5 || APP-PLUS
  51. const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
  52. //bottom: 胶囊底部距离屏幕顶部的距离
  53. //height: 胶囊高度
  54. //left: 胶囊左侧距离屏幕左侧的距离
  55. //right: 胶囊右侧距离屏幕左侧的距离
  56. //top: 胶囊顶部距离屏幕顶部的距离
  57. //width: 胶囊宽度
  58. // console.log(menuButtonInfo.width, menuButtonInfo.height, menuButtonInfo.top)
  59. // console.log('计算胶囊右侧距离屏幕右边距离', result.screenWidth - menuButtonInfo.right)
  60. let menuWidth = menuButtonInfo.width + 'px'
  61. let menuHeight = menuButtonInfo.height + 'px'
  62. let menuBorderRadius = menuButtonInfo.height / 2 + 'px'
  63. let menuRight = result.screenWidth - menuButtonInfo.right + 'px'
  64. let menuTop = menuButtonInfo.top + 'px'
  65. let contentTop = result.statusBarHeight + 44 + 'px'
  66. let menuInfo = {
  67. statusBarHeight: statusBarHeight,//状态栏高度----用来给自定义导航条页面的顶部导航条设计padding-top使用:目的留出系统的状态栏区域
  68. menuWidth: menuWidth,//右侧的胶囊宽度--用来给自定义导航条页面的左侧胶囊设置使用
  69. menuHeight: menuHeight,//右侧的胶囊高度--用来给自定义导航条页面的左侧胶囊设置使用
  70. menuBorderRadius: menuBorderRadius,//一半的圆角--用来给自定义导航条页面的左侧胶囊设置使用
  71. menuRight: menuRight,//右侧的胶囊距离右侧屏幕距离--用来给自定义导航条页面的左侧胶囊设置使用
  72. menuTop: menuTop,//右侧的胶囊顶部距离屏幕顶部的距离--用来给自定义导航条页面的左侧胶囊设置使用
  73. contentTop: contentTop,//内容区距离页面最上方的高度--用来给自定义导航条页面的内容区定位距离使用
  74. }
  75. uni.setStorageSync('menuInfo', menuInfo)
  76. //#endif
  77. },
  78. fail: (error) => {
  79. console.log(error)
  80. }
  81. })
  82. },
  83. onHide() {
  84. },
  85. computed: {
  86. ...mapGetters([
  87. 'storeConversationList',
  88. 'storeCurrentConversation',
  89. 'storeCurrentUserID',
  90. 'storeSelfInfo',
  91. 'storeRecvFriendApplications',
  92. 'storeRecvGroupApplications',
  93. 'storeHistoryMessageList',
  94. 'storeIsSyncing',
  95. 'storeGroupList'
  96. ]),
  97. contactBadgeRely() {
  98. return {
  99. recvFriendApplications: this.storeRecvFriendApplications,
  100. recvGroupApplications: this.storeRecvGroupApplications,
  101. userKey: this.storeCurrentUserID
  102. };
  103. }
  104. },
  105. methods: {
  106. ...mapActions('message', ['pushNewMessage', 'updateOneMessage', 'updateQuoteMessageRevoke', 'updateMessageNicknameAndFaceUrl']),
  107. ...mapActions('conversation', ['updateCurrentMemberInGroup']),
  108. ...mapActions('contact', [
  109. 'updateFriendInfo',
  110. 'pushNewFriend',
  111. 'updateBlackInfo',
  112. 'pushNewBlack',
  113. 'pushNewGroup',
  114. 'updateGroupInfo',
  115. 'pushNewRecvFriendApplition',
  116. 'updateRecvFriendApplition',
  117. 'pushNewSentFriendApplition',
  118. 'updateSentFriendApplition',
  119. 'pushNewRecvGroupApplition',
  120. 'updateRecvGroupApplition',
  121. 'pushNewSentGroupApplition',
  122. 'updateSentGroupApplition'
  123. ]),
  124. getRandomInt(min, max) {
  125. const minCeiled = Math.ceil(min);
  126. const maxFloored = Math.floor(max);
  127. return Math.floor(Math.random() * (maxFloored - minCeiled + 1) + minCeiled); // 包含最小值和最大值
  128. },
  129. checkLogin(){
  130. var data={};
  131. checkLogin(data).then(
  132. res => {
  133. if(res.code==200){
  134. this.openImLogin();
  135. }
  136. },
  137. rej => {}
  138. );
  139. },
  140. checkUpdate() {
  141. const updateManager = uni.getUpdateManager();
  142. updateManager.onCheckForUpdate(function(res) {
  143. // 请求完新版本信息的回调
  144. console.log('是否有新版本:', res.hasUpdate);
  145. });
  146. updateManager.onUpdateReady(function() {
  147. uni.showModal({
  148. title: '更新提示',
  149. content: '新版本已经准备好,是否重启小程序?',
  150. confirmText: '立即重启',
  151. confirmColor: '#2179f5',
  152. success(res) {
  153. if (res.confirm) {
  154. // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
  155. updateManager.applyUpdate();
  156. }
  157. }
  158. });
  159. });
  160. updateManager.onUpdateFailed(function() {
  161. // 新的版本下载失败
  162. uni.showModal({
  163. title: '更新提示',
  164. content: '新版本下载失败,请检查网络后重试。',
  165. showCancel: false
  166. });
  167. });
  168. },
  169. initOpenIm() {
  170. innerAudioContext = uni.createInnerAudioContext();
  171. innerAudioContext.autoplay = false;
  172. innerAudioContext.src = newMessage;
  173. this.setGlobalIMlistener();
  174. this.tryLogin();
  175. },
  176. setGlobalIMlistener() {
  177. // init
  178. const kickHander = (message) => {
  179. toastWithCallback(message, () => {
  180. uni.setStorageSync('AppToken',null);
  181. uni.removeStorage({key: "IMToken",});
  182. uni.removeStorage({key: "IMUserID",});
  183. uni.removeStorage({key: "IMHasLogin"});
  184. uni.$emit('loginOut');
  185. //callingModule?.endCall();
  186. //meetingModule?.endCall();
  187. });
  188. };
  189. let that=this;
  190. IMSDK.subscribe(IMSDK.IMEvents.OnKickedOffline, (data) => {
  191. kickHander('您的账号在其他设备登录,请重新登陆!');
  192. //that.removeImData();
  193. //that.openImLogin();
  194. });
  195. IMSDK.subscribe(IMSDK.IMEvents.OnUserTokenExpired, (data) => {
  196. //kickHander('您的登录已过期,请重新登陆!');
  197. that.removeImData();
  198. that.openImLogin();
  199. });
  200. IMSDK.subscribe(IMSDK.IMEvents.OnUserTokenInvalid, (data) => {
  201. //kickHander('您的登录已无效,请重新登陆!');
  202. that.removeImData();
  203. that.openImLogin();
  204. });
  205. // sync
  206. const syncStartHandler = ({ data }) => {
  207. this.$store.commit('user/SET_IS_SYNCING', true);
  208. this.$store.commit('user/SET_REINSTALL', data);
  209. };
  210. const syncProgressHandler = ({ data }) => {
  211. this.$store.commit('user/SET_PROGRESS', data);
  212. };
  213. const syncFinishHandler = () => {
  214. this.$store.dispatch('conversation/getConversationList');
  215. this.$store.dispatch('contact/getFriendList');
  216. this.$store.dispatch('contact/getGrouplist');
  217. this.$store.dispatch('conversation/getUnReadCount');
  218. this.$store.commit('user/SET_IS_SYNCING', false);
  219. uni.hideLoading();
  220. };
  221. const syncFailedHandler = () => {
  222. uni.hideLoading();
  223. uni.$u.toast('同步消息失败');
  224. this.$store.dispatch('conversation/getConversationList');
  225. this.$store.dispatch('conversation/getUnReadCount');
  226. this.$store.commit('user/SET_IS_SYNCING', false);
  227. };
  228. IMSDK.subscribe(IMSDK.IMEvents.OnSyncServerStart, syncStartHandler);
  229. IMSDK.subscribe(IMSDK.IMEvents.OnSyncServerFinish, syncFinishHandler);
  230. IMSDK.subscribe(IMSDK.IMEvents.OnSyncServerFailed, syncFailedHandler);
  231. IMSDK.subscribe(IMSDK.IMEvents.OnSyncServerProgress, syncProgressHandler);
  232. // self
  233. const selfInfoUpdateHandler = ({ data }) => {
  234. this.$store.commit('user/SET_SELF_INFO', {
  235. ...this.storeSelfInfo,
  236. ...data
  237. });
  238. this.updateMessageNicknameAndFaceUrl({
  239. sendID: data.userID,
  240. senderNickname: data.nickname,
  241. senderFaceUrl: data.faceURL
  242. });
  243. };
  244. IMSDK.subscribe(IMSDK.IMEvents.OnSelfInfoUpdated, selfInfoUpdateHandler);
  245. // message
  246. const newMessagesHandler = ({ data }) => {
  247. if (this.storeIsSyncing) {
  248. return;
  249. }
  250. data.forEach(this.handleNewMessage);
  251. };
  252. const c2cReadReceiptHandler = ({ data: receiptList }) => {
  253. if (receiptList[0].userID !== this.storeCurrentConversation.userID) {
  254. return;
  255. }
  256. receiptList.forEach((item) => {
  257. item.msgIDList.forEach((msgID) => {
  258. this.updateOneMessage({
  259. message: {
  260. clientMsgID: msgID
  261. },
  262. type: UpdateMessageTypes.KeyWords,
  263. keyWords: {
  264. key: 'isRead',
  265. value: true
  266. }
  267. });
  268. });
  269. });
  270. };
  271. const groupReadReceiptHandler = ({ data }) => {
  272. if (data.conversationID !== this.storeCurrentConversation.conversationID) {
  273. return;
  274. }
  275. data.groupMessageReadInfo.map((receipt) => {
  276. const oldMessage = this.storeHistoryMessageList.find((msg) => msg.clientMsgID === receipt.clientMsgID);
  277. if (oldMessage) {
  278. uni.$emit(PageEvents.GroupMessageReceipt, receipt);
  279. const newMessage = {
  280. ...oldMessage,
  281. isRead: true,
  282. attachedInfoElem: {
  283. ...oldMessage.attachedInfoElem,
  284. groupHasReadInfo: {
  285. hasReadCount: receipt.hasReadCount,
  286. unreadCount: receipt.unreadCount
  287. }
  288. }
  289. };
  290. console.log(newMessage);
  291. this.updateOneMessage({ message: newMessage });
  292. }
  293. });
  294. console.log(data);
  295. };
  296. const newRecvMessageRevokedHandler = ({ data: revokedMessage }) => {
  297. if (!this.storeCurrentConversation.conversationID) {
  298. return;
  299. }
  300. this.updateOneMessage({
  301. message: { clientMsgID: revokedMessage.clientMsgID },
  302. type: UpdateMessageTypes.KeyWords,
  303. keyWords: [
  304. {
  305. key: 'contentType',
  306. value: MessageType.RevokeMessage
  307. },
  308. {
  309. key: 'notificationElem',
  310. value: {
  311. detail: JSON.stringify(revokedMessage)
  312. }
  313. }
  314. ]
  315. });
  316. this.updateQuoteMessageRevoke({
  317. clientMsgID: revokedMessage.clientMsgID
  318. });
  319. };
  320. const inputStatusChanged = ({ data }) => {
  321. if (data.userID === this.storeCurrentConversation.userID && data.conversationID === this.storeCurrentConversation.conversationID) {
  322. if (data.platformIDs.length > 0) {
  323. uni.$emit(PageEvents.TypingUpdate);
  324. }
  325. }
  326. };
  327. IMSDK.subscribe(IMSDK.IMEvents.OnRecvNewMessages, newMessagesHandler);
  328. IMSDK.subscribe(IMSDK.IMEvents.OnInputStatusChanged, inputStatusChanged);
  329. IMSDK.subscribe(IMSDK.IMEvents.OnRecvC2CReadReceipt, c2cReadReceiptHandler);
  330. IMSDK.subscribe(IMSDK.IMEvents.OnRecvGroupReadReceipt, groupReadReceiptHandler);
  331. IMSDK.subscribe(IMSDK.IMEvents.OnNewRecvMessageRevoked, newRecvMessageRevokedHandler);
  332. // friend
  333. const friendInfoChangeHandler = ({ data }) => {
  334. uni.$emit(IMSDK.IMEvents.OnFriendInfoChanged, { data });
  335. if (data.userID === this.storeCurrentConversation?.userID) {
  336. this.updateMessageNicknameAndFaceUrl({
  337. sendID: data.userID,
  338. senderNickname: data.remark || data.nickname,
  339. senderFaceUrl: data.faceURL
  340. });
  341. this.$store.commit('conversation/SET_CURRENT_CONVERSATION', { ...this.storeCurrentConversation, showName: data.remark || data.nickname });
  342. }
  343. console.log(this.storeConversationList);
  344. this.updateFriendInfo({friendInfo: data});
  345. };
  346. const friendAddedHandler = ({ data }) => {
  347. this.pushNewFriend(data);
  348. };
  349. const friendDeletedHander = ({ data }) => {
  350. this.updateFriendInfo({
  351. friendInfo: data,
  352. isRemove: true
  353. });
  354. };
  355. IMSDK.subscribe(IMSDK.IMEvents.OnFriendInfoChanged, friendInfoChangeHandler);
  356. IMSDK.subscribe(IMSDK.IMEvents.OnFriendAdded, friendAddedHandler);
  357. IMSDK.subscribe(IMSDK.IMEvents.OnFriendDeleted, friendDeletedHander);
  358. // blacklist
  359. const blackAddedHandler = ({ data }) => {
  360. this.pushNewBlack(data);
  361. };
  362. const blackDeletedHandler = ({ data }) => {
  363. this.updateBlackInfo({
  364. blackInfo: data,
  365. isRemove: true
  366. });
  367. };
  368. IMSDK.subscribe(IMSDK.IMEvents.OnBlackAdded, blackAddedHandler);
  369. IMSDK.subscribe(IMSDK.IMEvents.OnBlackDeleted, blackDeletedHandler);
  370. // group
  371. const joinedGroupAddedHandler = ({ data }) => {
  372. uni.$emit(IMSDK.IMEvents.OnJoinedGroupAdded, { data });
  373. this.pushNewGroup(data);
  374. };
  375. const joinedGroupDeletedHandler = ({ data }) => {
  376. uni.$emit(IMSDK.IMEvents.OnJoinedGroupDeleted, { data });
  377. this.updateGroupInfo({
  378. groupInfo: data,
  379. isRemove: true
  380. });
  381. };
  382. const groupInfoChangedHandler = ({ data }) => {
  383. this.updateGroupInfo({
  384. groupInfo: data
  385. });
  386. };
  387. const groupMemberInfoChangedHandler = ({ data }) => {
  388. uni.$emit(IMSDK.IMEvents.OnGroupMemberInfoChanged, { data });
  389. if (data.groupID === this.storeCurrentConversation?.groupID) {
  390. this.updateMessageNicknameAndFaceUrl({
  391. sendID: data.userID,
  392. senderNickname: data.nickname,
  393. senderFaceUrl: data.faceURL
  394. });
  395. this.updateCurrentMemberInGroup(data);
  396. }
  397. };
  398. IMSDK.subscribe(IMSDK.IMEvents.OnJoinedGroupAdded, joinedGroupAddedHandler);
  399. IMSDK.subscribe(IMSDK.IMEvents.OnJoinedGroupDeleted, joinedGroupDeletedHandler);
  400. IMSDK.subscribe(IMSDK.IMEvents.OnGroupInfoChanged, groupInfoChangedHandler);
  401. IMSDK.subscribe(IMSDK.IMEvents.OnGroupMemberInfoChanged, groupMemberInfoChangedHandler);
  402. // application
  403. const friendApplicationNumHandler = ({ data }) => {
  404. const isRecv = data.toUserID === this.storeCurrentUserID;
  405. if (isRecv) {
  406. this.pushNewRecvFriendApplition(data);
  407. } else {
  408. this.pushNewSentFriendApplition(data);
  409. }
  410. };
  411. const friendApplicationAccessHandler = ({ data }) => {
  412. const isRecv = data.toUserID === this.storeCurrentUserID;
  413. if (isRecv) {
  414. this.updateRecvFriendApplition({
  415. application: data
  416. });
  417. } else {
  418. this.updateSentFriendApplition({
  419. application: data
  420. });
  421. }
  422. };
  423. const groupApplicationNumHandler = ({ data }) => {
  424. const isRecv = data.userID !== this.storeCurrentUserID;
  425. if (isRecv) {
  426. this.pushNewRecvGroupApplition(data);
  427. } else {
  428. this.pushNewSentGroupApplition(data);
  429. }
  430. };
  431. const groupApplicationAccessHandler = ({ data }) => {
  432. const isRecv = data.userID !== this.storeCurrentUserID;
  433. if (isRecv) {
  434. this.updateRecvGroupApplition({
  435. application: data
  436. });
  437. } else {
  438. this.updateSentGroupApplition({
  439. application: data
  440. });
  441. }
  442. };
  443. IMSDK.subscribe(IMSDK.IMEvents.OnFriendApplicationAdded, friendApplicationNumHandler);
  444. IMSDK.subscribe(IMSDK.IMEvents.OnFriendApplicationAccepted, friendApplicationAccessHandler);
  445. IMSDK.subscribe(IMSDK.IMEvents.OnFriendApplicationRejected, friendApplicationAccessHandler);
  446. IMSDK.subscribe(IMSDK.IMEvents.OnGroupApplicationAdded, groupApplicationNumHandler);
  447. IMSDK.subscribe(IMSDK.IMEvents.OnGroupApplicationAccepted, groupApplicationAccessHandler);
  448. IMSDK.subscribe(IMSDK.IMEvents.OnGroupApplicationRejected, groupApplicationAccessHandler);
  449. // conversation
  450. const totalUnreadCountChangedHandler = ({ data }) => {
  451. if (this.storeIsSyncing) {
  452. return;
  453. }
  454. this.$store.commit('conversation/SET_UNREAD_COUNT', data);
  455. };
  456. const newConversationHandler = ({ data }) => {
  457. if (this.storeIsSyncing) {
  458. return;
  459. }
  460. const result = [...data, ...this.storeConversationList];
  461. this.$store.commit('conversation/SET_CONVERSATION_LIST', conversationSort(result));
  462. };
  463. const conversationChangedHandler = ({ data }) => {
  464. if (this.storeIsSyncing) {
  465. return;
  466. }
  467. let filterArr = [];
  468. console.log("qxj conversationChangedHandler:::");
  469. console.log(data);
  470. const chids = data.map((ch) => ch.conversationID);
  471. filterArr = this.storeConversationList.filter((tc) => !chids.includes(tc.conversationID));
  472. const idx = data.findIndex((c) => c.conversationID === this.storeCurrentConversation.conversationID);
  473. if (idx !== -1) this.$store.commit('conversation/SET_CURRENT_CONVERSATION', data[idx]);
  474. const result = [...data, ...filterArr];
  475. this.$store.commit('conversation/SET_CONVERSATION_LIST', conversationSort(result));
  476. };
  477. IMSDK.subscribe(IMSDK.IMEvents.OnTotalUnreadMessageCountChanged, totalUnreadCountChangedHandler);
  478. IMSDK.subscribe(IMSDK.IMEvents.OnNewConversation, newConversationHandler);
  479. IMSDK.subscribe(IMSDK.IMEvents.OnConversationChanged, conversationChangedHandler);
  480. const insertInCurrentConversation = (newServerMsg) => {
  481. return newServerMsg.sendID === this.$store.getters.storeCurrentConversation.userID || newServerMsg.recvID === this.$store.getters.storeCurrentConversation.userID;
  482. };
  483. const onNativeCallEndHandler = async ({ invitation, duration, status }) => {
  484. uni.$emit(PageEvents.NativeCallEnd);
  485. if (!status || invitation.groupID) {
  486. return;
  487. }
  488. const type = invitation.mediaType === 'video' ? CustomType.VideoCall : CustomType.VoiceCall;
  489. const customData = {
  490. customType: CustomType.Call,
  491. data: { type, duration: secFormat(duration), status }
  492. };
  493. // uni.clearStorageSync();
  494. const nativeCallList = uni.getStorageSync(`${this.$store.getters.storeCurrentUserID}_nativecall`) || [];
  495. const isSelf = invitation.inviterUserID === this.$store.getters.storeCurrentUserID;
  496. const data = { ...invitation, duration, isSelf, type, time: new Date().getTime() };
  497. uni.setStorage({
  498. key: `${this.$store.getters.storeCurrentUserID}_nativecall`,
  499. data: [...nativeCallList, data]
  500. });
  501. const message = await IMSDK.asyncApi(IMMethods.CreateCustomMessage, IMSDK.uuid(), {
  502. data: JSON.stringify(customData),
  503. extension: '',
  504. description: 'RTC'
  505. });
  506. const recvID = invitation.inviteeUserIDList[0];
  507. IMSDK.asyncApi(IMSDK.IMMethods.InsertSingleMessageToLocalStorage, IMSDK.uuid(), {
  508. message,
  509. recvID,
  510. sendID: invitation.inviterUserID
  511. }).then(({ data }) => {
  512. if (insertInCurrentConversation(data)) {
  513. this.$store.dispatch('message/pushNewMessage', data);
  514. setTimeout(() => uni.$emit(PageEvents.ScrollToBottom, true));
  515. }
  516. }).catch((err) => {
  517. console.log(err);
  518. });
  519. };
  520. const onNativeInviteHandler = async (data) => {
  521. // uni.$u.toast("onNativeInviteHandler")
  522. uni.$u.route('/pages_im/pages/common/contactChoose/index', {
  523. type: ContactChooseTypes.InviteMeeting,
  524. forwardMessage: encodeURIComponent(JSON.stringify(data.data))
  525. });
  526. };
  527. IMSDK.subscribe('onNativeCallEnd', onNativeCallEndHandler);
  528. IMSDK.subscribe('Native_InviteUser', onNativeInviteHandler);
  529. },
  530. openImLogin() {
  531. let that = this;
  532. var userId=uni.getStorageSync('userId');
  533. var avatar=uni.getStorageSync('avatar');
  534. var nickName=uni.getStorageSync('nickName');
  535. var uid = 'U' + userId;
  536. let IMToken = uni.getStorageSync('IMToken');
  537. let IMUserID = uid
  538. let reqData = { userID: uid, nickName: nickName, avatar: avatar };
  539. //if(!!IMToken){
  540. openImLoginApi(
  541. reqData,
  542. IMToken,
  543. IMUserID,
  544. function (token) {
  545. that.tryLogin();
  546. },
  547. function () {}
  548. );
  549. //}
  550. },
  551. async tryLogin() {
  552. const initStore = () => {
  553. uni.setStorageSync('IMHasLogin', 1);
  554. this.$store.dispatch('user/initCache');
  555. this.$store.dispatch('user/getSelfInfo');
  556. //this.$store.dispatch('conversation/getConversationList');
  557. this.$store.dispatch('conversation/getUnReadCount');
  558. // this.$store.dispatch("contact/getFriendList");
  559. // this.$store.dispatch("contact/getGrouplist");
  560. // this.$store.dispatch('contact/getBlacklist');
  561. // this.$store.dispatch('contact/getRecvFriendApplications');
  562. // this.$store.dispatch('contact/getSentFriendApplications');
  563. // this.$store.dispatch('contact/getRecvGroupApplications');
  564. // this.$store.dispatch('contact/getSentGroupApplications');
  565. };
  566. let IMToken = uni.getStorageSync('IMToken');
  567. let IMUserID = uni.getStorageSync('IMUserID');
  568. //1 未登录 2 登录中 3 已登录
  569. const loginStatus = await IMSDK.asyncApi(IMSDK.IMMethods.GetLoginStatus, IMSDK.uuid());
  570. console.log("qxj loginStatus:"+loginStatus);
  571. if (loginStatus === 3) {
  572. initStore();
  573. return;
  574. }
  575. //callingModule?.initModule();
  576. let platformID=5
  577. // #ifdef H5
  578. platformID=5
  579. // #endif
  580. // #ifdef MP-WEIXIN
  581. platformID=6
  582. // #endif
  583. console.log("qxj platformID:"+platformID);
  584. if (IMToken && IMUserID) {
  585. IMSDK.asyncApi(IMSDK.IMMethods.Login, IMSDK.uuid(), {
  586. userID: IMUserID,
  587. token: IMToken,
  588. platformID:platformID,
  589. apiAddr: config.getApiUrl(),
  590. wsAddr: config.getWsUrl(),
  591. logLevel: 1,
  592. }).then(initStore).catch((err) => {
  593. console.log('qxj initStore error:' + JSON.stringify(err));
  594. uni.removeStorage({ key: 'IMToken' });
  595. });
  596. } else{
  597. this.checkLogin()
  598. }
  599. },
  600. async newMessageNotify(newServerMsg) {
  601. if (this.storeIsSyncing) {
  602. return;
  603. }
  604. const disableNotify = uni.getStorageSync(`${this.storeCurrentUserID}_DisableNotify`);
  605. if (disableNotify || this.storeSelfInfo.globalRecvMsgOpt !== MessageReceiveOptType.Nomal) {
  606. return;
  607. }
  608. let cveItem = [...this.storeConversationList, ...cacheConversationList].find((conversation) => {
  609. if (newServerMsg.sessionType === SessionType.WorkingGroup) {
  610. return newServerMsg.groupID === conversation.groupID;
  611. }
  612. return newServerMsg.sendID === conversation.userID;
  613. });
  614. if (!cveItem) {
  615. try {
  616. const { data } = await IMSDK.asyncApi(IMSDK.IMMethods.GetOneConversation, IMSDK.uuid(), {
  617. sourceID: newServerMsg.groupID || newServerMsg.sendID,
  618. sessionType: newServerMsg.sessionType
  619. });
  620. cveItem = data;
  621. cacheConversationList = [...cacheConversationList, data];
  622. } catch (e) {
  623. return;
  624. }
  625. }
  626. if (cveItem.recvMsgOpt !== MessageReceiveOptType.Nomal) {
  627. return;
  628. }
  629. // uni.createPushMessage({
  630. // content: `${newServerMsg.senderNickname}: ${parseMessageByType(newServerMsg)}`,
  631. // payload: {
  632. // sessionType: newServerMsg.sessionType,
  633. // sourceID: newServerMsg.groupID || newServerMsg.sendID,
  634. // }
  635. // });
  636. // const notificationFun = () => {
  637. // const isSelf = newServerMsg.sendID === this.$store.getters.storeCurrentUserID;
  638. // if (isSelf) return;
  639. // const isSingle = newServerMsg.groupID ? false : true;
  640. // console.log(this.storeGroupList, newServerMsg);
  641. // const group = this.storeGroupList.filter((group) => group.groupID === newServerMsg.groupID);
  642. // const title = isSingle ? newServerMsg.senderNickname : group[0].groupName;
  643. // const desc = parseMessageByType(newServerMsg);
  644. // console.log('notification', title, desc);
  645. // notification.showNotice(0, title, desc, () => {
  646. // prepareConversationState(cveItem);
  647. // });
  648. // };
  649. // notificationFun();
  650. // const platform = uni.getSystemInfoSync().platform;
  651. // if (platform == 'ios') {
  652. // if (this.storeSelfInfo.allowVibration === 1) {
  653. // plus.device.vibrate();
  654. // }
  655. // if (this.storeSelfInfo.allowBeep === 1) {
  656. // innerAudioContext.play();
  657. // // plus.device.beep();
  658. // }
  659. // } else if (platform == 'android') {
  660. // if (this.storeSelfInfo.allowVibration === 1) {
  661. // plus.device.vibrate(500);
  662. // }
  663. // if (this.storeSelfInfo.allowBeep === 1) {
  664. // let main = plus.android.runtimeMainActivity();
  665. // let RingtoneManager = plus.android.importClass('android.media.RingtoneManager');
  666. // let uri = RingtoneManager.getActualDefaultRingtoneUri(main, RingtoneManager.TYPE_NOTIFICATION);
  667. // let MediaPlayer = plus.android.importClass('android.media.MediaPlayer');
  668. // let player = MediaPlayer.create(main, uri);
  669. // player.setLooping(false);
  670. // player.prepare();
  671. // player.start();
  672. // }
  673. // }
  674. },
  675. handleNewMessage(newServerMsg) {
  676. console.log("---qxj newServerMsg");
  677. console.log(newServerMsg);
  678. if (this.inCurrentConversation(newServerMsg)) {
  679. const isSingleMessage = newServerMsg.sessionType === SessionType.Single;
  680. if (isSingleMessage) {
  681. uni.$u.throttle(() => uni.$emit(PageEvents.OnlineStateCheck), 2000);
  682. if(newServerMsg.ex!=null&&newServerMsg.ex!=''){
  683. var json=JSON.parse(newServerMsg.ex);
  684. this.$store.commit("timStore/setType",json.type);
  685. this.$store.commit("timStore/setImType", json.imType);
  686. this.$store.commit("timStore/setOrderId",json.orderId);
  687. this.$store.commit("timStore/setOrderType",json.orderType);
  688. this.$store.commit("timStore/setFollowId",json.followId);
  689. if(json.type==="finishInquiry"){
  690. this.$store.commit("timStore/setImType", 0);
  691. uni.navigateTo({ url: "/pages_order/pingOrder?orderId="+json.orderId })
  692. }
  693. else if(json.type==="startInquiry"){
  694. }
  695. else if(json.type==="inquiry"){
  696. }
  697. else if(json.type==="startFollow"){
  698. }
  699. else if(json.type==="follow"){
  700. }
  701. else if(json.type==="finishFollow"){
  702. }
  703. else if(json.type==="startDrugReport"){
  704. }
  705. else if(json.type==="finishDrugReport"){
  706. }
  707. else if(json.type==="drugReport"){
  708. }
  709. }
  710. }
  711. if (newServerMsg.contentType === MessageType.TypingMessage) {
  712. if (isSingleMessage) {
  713. uni.$emit(PageEvents.TypingUpdate);
  714. }
  715. }
  716. else {
  717. if (newServerMsg.contentType === MessageType.RevokeMessage) {
  718. }
  719. else {
  720. newServerMsg.isAppend = true;
  721. this.pushNewMessage(newServerMsg);
  722. setTimeout(() => uni.$emit(PageEvents.ScrollToBottom, true));
  723. }
  724. uni.$u.debounce(this.markConversationAsRead, 2000);
  725. }
  726. }
  727. else {
  728. if (newServerMsg.contentType !== MessageType.TypingMessage) {
  729. console.log("---qxj not inCurrentConversation");
  730. uni.$u.throttle(() => this.newMessageNotify(newServerMsg), 500);
  731. setTimeout(() => {
  732. this.$store.dispatch('conversation/getUnReadCount');
  733. },500);
  734. }
  735. }
  736. },
  737. inCurrentConversation(newServerMsg) {
  738. switch (newServerMsg.sessionType) {
  739. case SessionType.Single:
  740. return (
  741. newServerMsg.sendID === this.storeCurrentConversation.userID ||
  742. (newServerMsg.sendID === this.storeCurrentUserID && newServerMsg.recvID === this.storeCurrentConversation.userID)
  743. );
  744. case SessionType.WorkingGroup:
  745. return newServerMsg.groupID === this.storeCurrentConversation.groupID;
  746. case SessionType.Notification:
  747. return newServerMsg.sendID === this.storeCurrentConversation.userID;
  748. default:
  749. return false;
  750. }
  751. },
  752. markConversationAsRead() {
  753. IMSDK.asyncApi(IMSDK.IMMethods.MarkConversationMessageAsRead, IMSDK.uuid(), this.storeCurrentConversation.conversationID);
  754. },
  755. removeImData(){
  756. uni.removeStorage({ key: 'IMToken' });
  757. uni.removeStorage({ key: 'IMUserID' });
  758. },
  759. getRuntimePlatform() {
  760. const systemInfo = uni.getSystemInfoSync();
  761. const compilePlatform = process.env.UNI_PLATFORM;
  762. //1:iOS,2:Android,3:Windows,4:OSX,5:WEB,6:小程序,7:linux,8:AndroidPad,9:IPad,10:Admin
  763. let platformType=5;
  764. // H5 环境
  765. if (compilePlatform === 'h5') platformType= 5;
  766. // 小程序环境
  767. if (compilePlatform.startsWith('mp-')) {
  768. const mpType = compilePlatform.split('-')[1]; // 如 weixin/alipay
  769. platformType=6;
  770. }
  771. // App 环境
  772. if (compilePlatform === 'app-plus') {
  773. if(systemInfo.platform.toLowerCase() === 'android'){
  774. platformType=2;
  775. }
  776. if(systemInfo.platform.toLowerCase() === 'ios'){
  777. platformType=1;
  778. }
  779. }
  780. console.log("----qxj platformType:"+platformType);
  781. uni.showToast({ title:" platformType:"+platformType,icon:'none', duration: 2000 });
  782. return platformType;
  783. },
  784. getDicts(){
  785. getDicts().then(
  786. res => {
  787. if(res.code==200){
  788. uni.setStorageSync('dicts',JSON.stringify(res));
  789. }
  790. },
  791. rej => {}
  792. );
  793. },
  794. }
  795. };
  796. </script>
  797. <style lang="scss">
  798. @import "@/assets/css/theme.scss";
  799. /*每个页面公共css */
  800. // #ifdef VUE3
  801. @import "@/uni_modules/uview-plus/index.scss";
  802. // #endif
  803. // #ifndef VUE3
  804. @import "uview-ui/index.scss";
  805. // #endif
  806. view{
  807. box-sizing: border-box;
  808. }
  809. .ellipsis{
  810. overflow: hidden;
  811. text-overflow: ellipsis;
  812. white-space: nowrap;
  813. }
  814. .ellipsis2{
  815. overflow:hidden;
  816. text-overflow:ellipsis;
  817. display:-webkit-box;
  818. -webkit-box-orient:vertical;
  819. -webkit-line-clamp:2;
  820. }
  821. .no-data-box{
  822. box-sizing: border-box;
  823. width: 100%;
  824. padding: 200rpx 50rpx;
  825. text-align: center;
  826. flex-direction: column;
  827. justify-content: center;
  828. align-items: center;
  829. image{
  830. width: 200upx;
  831. height: 150upx;
  832. }
  833. .empty-title{
  834. margin-top: 20rpx;
  835. font-size: 28rpx;
  836. color: #bbbbbb;
  837. }
  838. }
  839. .doctor-box{
  840. margin-top: 15rpx;
  841. padding: 20rpx 0rpx 0rpx;
  842. display: flex;
  843. flex-direction: column;
  844. align-items: flex-start;
  845. justify-content: flex-start;
  846. .doctor{
  847. width: 100%;
  848. margin-bottom: 15rpx;
  849. background: #fff;
  850. padding: 15rpx;
  851. display: flex;
  852. flex-direction: column;
  853. align-items: flex-start;
  854. justify-content: flex-start;
  855. &:last-child{
  856. margin-bottom: 0rpx;
  857. }
  858. .item{
  859. width: 100%;
  860. display: flex;
  861. align-items: flex-start;
  862. justify-content: flex-start;
  863. .left{
  864. .head-box{
  865. width:92rpx;
  866. height:92rpx;
  867. position: relative;
  868. .isline{
  869. width:92rpx;
  870. height:92rpx;
  871. border-radius: 50%;
  872. border: 2rpx solid #2EDAD4;
  873. display: flex;
  874. align-items: center;
  875. justify-content: center;
  876. position: absolute;
  877. bottom: 0rpx;
  878. .img{
  879. position: absolute;
  880. bottom: 1rpx;
  881. width:75rpx;
  882. height:35rpx;
  883. image{
  884. width:75rpx;
  885. height:35rpx;
  886. }
  887. .name{
  888. width:75rpx;
  889. height:35rpx;
  890. bottom: -3rpx;
  891. text-align: center;
  892. position: absolute;
  893. font-size: 16upx;
  894. font-family: PingFang SC;
  895. font-weight: bold;
  896. color: #ffffff;
  897. }
  898. }
  899. }
  900. .doc-img{
  901. border-radius: 50%;
  902. width:100%;
  903. height:100%;
  904. }
  905. }
  906. }
  907. .right{
  908. width: calc(100% - 100rpx);
  909. margin-left: 20rpx;
  910. display: flex;
  911. flex-direction: column;
  912. align-items: flex-start;
  913. justify-content: flex-start;
  914. .doc-box{
  915. display: flex;
  916. align-items: center;
  917. justify-content: space-between;
  918. .doc-name{
  919. font-size: 32upx;
  920. font-family: PingFang SC;
  921. font-weight: bold;
  922. color: #111111;
  923. }
  924. .doc-position{
  925. margin-left: 16rpx;
  926. font-size: 26upx;
  927. font-weight: bold;
  928. font-family: PingFang SC;
  929. color: #2A2B2E;
  930. }
  931. .doc-dept{
  932. margin-left: 16rpx;
  933. font-size: 26upx;
  934. font-weight: bold;
  935. font-family: PingFang SC;
  936. color: #2A2B2E;
  937. }
  938. }
  939. .hospital-box{
  940. display: flex;
  941. align-items: center;
  942. justify-content: flex-start;
  943. margin-top: 10rpx;
  944. .tag{
  945. display: flex;
  946. align-items: center;
  947. justify-content: center;
  948. background-color: #4FC06B;
  949. border-radius: 10rpx;
  950. padding: 5rpx 10rpx;
  951. font-size: 20upx;
  952. font-weight: bold;
  953. font-family: PingFang SC;
  954. color: #ffffff;
  955. }
  956. .name{
  957. margin-left: 6rpx;
  958. font-size: 26upx;
  959. font-weight: bold;
  960. font-family: PingFang SC;
  961. color: #2A2B2E;
  962. }
  963. }
  964. .doc-spec{
  965. width: 100%;
  966. display: flex;
  967. align-items: center;
  968. justify-content: flex-start;
  969. margin-top: 15rpx;
  970. .spec{
  971. font-size: 26upx;
  972. font-family: PingFang SC;
  973. color: #626468;
  974. }
  975. }
  976. .doc-count{
  977. margin-top: 15rpx;
  978. display: flex;
  979. align-items: center;
  980. justify-content: flex-start;
  981. .name{
  982. font-size: 24upx;
  983. font-family: PingFang SC;
  984. color: #9B9B9B;
  985. }
  986. .count{
  987. margin: 0rpx 5rpx;
  988. font-size: 24upx;
  989. font-family: PingFang SC;
  990. color: #2A2B2E;
  991. }
  992. }
  993. .doc-price{
  994. width: 100%;
  995. margin-top: 15rpx;
  996. display: flex;
  997. align-items: center;
  998. justify-content: flex-start;
  999. .btn{
  1000. display: flex;
  1001. align-items: center;
  1002. justify-content: center;
  1003. background-color: #2583EB;
  1004. padding: 15rpx 30rpx;
  1005. border-radius: 30rpx;
  1006. font-size: 26upx;
  1007. font-family: PingFang SC;
  1008. color: #fff;
  1009. }
  1010. }
  1011. }
  1012. }
  1013. }
  1014. }
  1015. </style>
  1016. <style lang="less">
  1017. /*每个页面公共css */
  1018. @import './assets/iconfont/iconfont.css';
  1019. @import './assets/css/common.less';
  1020. /* 全局flex样式 */
  1021. @import './common/css/flexCommon.css';
  1022. </style>