Index.vue 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. <script setup>
  2. import Aside from "./component/Aside.vue";
  3. import { useStore } from "vuex";
  4. import { computed, ref,watch } from "vue";
  5. import moment from "moment";
  6. import { useRouter } from "vue-router";
  7. const router=useRouter()
  8. const store = useStore();
  9. const userInfo = computed(() => store.state.userInfo);
  10. const lastTime = computed(() => {
  11. let timeArr = [];
  12. store.state.userInfo.permission_list &&
  13. store.state.userInfo.permission_list.forEach((item) => {
  14. item.permission_list.forEach((item2) => {
  15. timeArr.push(new Date(item2.end_date));
  16. });
  17. });
  18. let maxTime = Math.max(...timeArr);
  19. if (timeArr.length === 0) {
  20. return "";
  21. } else {
  22. return moment(maxTime).format("YYYY.MM.DD");
  23. }
  24. });
  25. import { apiGetPermissionList } from "@/api/common.js";
  26. let permissionList = ref([]);
  27. const getPermissionList = async () => {
  28. const res = await apiGetPermissionList();
  29. if (res.code === 200) {
  30. permissionList.value = res.data;
  31. }
  32. };
  33. getPermissionList();
  34. let permission_list_str = computed(() => {
  35. let hasArr = [];
  36. store.state.userInfo.permission_list &&
  37. store.state.userInfo.permission_list.forEach((item) => {
  38. item.permission_list.forEach((item2) => {
  39. hasArr.push(item2.name);
  40. });
  41. });
  42. let arr = permissionList.value.filter((item) => {
  43. if (hasArr.find((e) => e === item.permission_name)) return item;
  44. });
  45. let arr2=arr.map(item=>item.name)
  46. return arr2.join('/')
  47. });
  48. //我的中点击去申请权限
  49. import { ElMessageBox } from 'element-plus'
  50. import {apiLastApplyRecord} from '@/api/user'
  51. const handleGoApplyPermission=async ()=>{
  52. const res=await apiLastApplyRecord()
  53. if(res.code===200){
  54. if(res.data){
  55. const htmlStr=`<p style="text-align:center;">您已提交过申请,请耐心等待</p>`
  56. ElMessageBox({
  57. title:'申请提醒',
  58. message:htmlStr,
  59. dangerouslyUseHTMLString: true,
  60. confirmButtonText:'知道了',
  61. confirmButtonClass:'self-elmessage-confirm-btn'
  62. })
  63. }else{
  64. router.push({
  65. path:'/apply/permission',
  66. query:{
  67. source:1,
  68. fromPage:'我的'
  69. }
  70. })
  71. }
  72. }
  73. }
  74. // 全局返回按钮
  75. const goBack=()=>{
  76. router.go(-1)
  77. }
  78. // 音频切换
  79. const handleAudioChange=(e)=>{
  80. store.commit('changeAudio',e)
  81. }
  82. // 关闭音频
  83. const handleAudioClose=()=>{
  84. store.commit('closeAudio')
  85. }
  86. //音频状态改变
  87. const handleAudioStatus=(e)=>{
  88. store.commit('audioStatusChange',e)
  89. }
  90. const globalAudioIns=ref(null)
  91. store.state.audioData.INS=globalAudioIns
  92. </script>
  93. <template>
  94. <div class="layout-wrap">
  95. <el-container style="width: 100%;height:100%">
  96. <Aside></Aside>
  97. <el-main>
  98. <img v-if="$route.meta.hasBack" @click="goBack" class="back-icon" src="@/assets/icon-back.png" alt="">
  99. <!-- <router-view /> -->
  100. <router-view v-slot="{ Component }">
  101. <keep-alive>
  102. <component :is="Component" v-if="$route.meta.keepAlive" />
  103. </keep-alive>
  104. <component :is="Component" v-if="!$route.meta.keepAlive" />
  105. </router-view>
  106. </el-main>
  107. <!-- 个人信息模块 -->
  108. <div class="userinfo-wrap">
  109. <el-popover :width="400" popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 20px;">
  110. <template #reference>
  111. <img class="icon-scan" src="@/assets/icon-scan.png" alt="" />
  112. </template>
  113. <template #default>
  114. <div class="flex" style="justify-content: space-between">
  115. <div style="flex: 1; text-align: center">
  116. <img style="width: 121px" src="@/assets/xcx-img.png" alt="" />
  117. <p>手机扫码<br />体验更多小程序功能</p>
  118. </div>
  119. <div style="flex: 1; text-align: center">
  120. <img style="width: 121px" src="@/assets/gzh-img.png" alt="" />
  121. <p>关注弘则研报公众号<br />及时获取活动和报告通知</p>
  122. </div>
  123. </div>
  124. </template>
  125. </el-popover>
  126. <el-popover :width="400" popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 20px;">
  127. <template #reference>
  128. <el-avatar shape="square" :size="50" :src="$store.state.globalImgUrls.defaultAvatar"></el-avatar>
  129. </template>
  130. <template #default>
  131. <div class="userinfo-box" v-if="userInfo">
  132. <div class="top">
  133. <el-avatar shape="square" :size="50" :src="$store.state.globalImgUrls.defaultAvatar"></el-avatar>
  134. <p style="font-size: 20px">{{ userInfo.real_name||'--' }}</p>
  135. <p>{{ userInfo.mobile||userInfo.email }}</p>
  136. </div>
  137. <div class="flex info-item">
  138. <div class="label">公司</div>
  139. <div class="con">{{ userInfo.company_name||'--' }}</div>
  140. </div>
  141. <div class="flex info-item">
  142. <div class="label">品种权限</div>
  143. <div class="con" v-if="userInfo.status=='冻结'||(userInfo.status=='试用'&&userInfo.is_suspend==1)">
  144. <span>暂无权限</span>
  145. <span class="btn">联系销售</span>
  146. </div>
  147. <div class="con" v-else-if="userInfo.permission_list.length==0">
  148. <span>暂无权限</span>
  149. <span class="btn" @click="handleGoApplyPermission">立即申请</span>
  150. </div>
  151. <div class="con" v-else>{{permission_list_str}}</div>
  152. </div>
  153. <div class="flex info-item">
  154. <div class="label">服务截至日期</div>
  155. <div class="con">{{ lastTime }}</div>
  156. </div>
  157. </div>
  158. </template>
  159. </el-popover>
  160. </div>
  161. </el-container>
  162. <!-- 全局音频模块 -->
  163. <div class="global-audio-box" v-if="$store.state.audioData.list.length>0" v-drag="{'zIndex':100}">
  164. <div style="height:10px;cursor: move;">
  165. <svg @click="handleAudioClose" class="icon" width="20" height="20" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" data-v-042ca774=""><path fill="currentColor" d="M764.288 214.592L512 466.88 259.712 214.592a31.936 31.936 0 00-45.12 45.12L466.752 512 214.528 764.224a31.936 31.936 0 1045.12 45.184L512 557.184l252.288 252.288a31.936 31.936 0 0045.12-45.12L557.12 512.064l252.288-252.352a31.936 31.936 0 10-45.12-45.184z"></path></svg>
  166. </div>
  167. <h2 style="text-align:center;font-size:14px;padding:0 20px">{{$store.state.audioData.list[$store.state.audioData.index].voiceName}}</h2>
  168. <audio
  169. controls
  170. autoplay
  171. @ended="handleAudioChange('auto')"
  172. @pause="handleAudioStatus('paused')"
  173. @play="handleAudioStatus('paly')"
  174. :src="$store.state.audioData.list[$store.state.audioData.index].voiceUrl"
  175. ref="globalAudioIns"
  176. ></audio>
  177. <div style="text-align:center;margin:4px 0 10px 0">
  178. <img src="@/assets/audio-before-grey.png" alt="" style="width:30px;margin-right:20px;cursor: pointer;" @click="handleAudioChange('before')">
  179. <img src="@/assets/audio-before-grey.png" alt="" style="width:30px;transform: rotate(180deg);cursor: pointer;" @click="handleAudioChange('next')">
  180. </div>
  181. </div>
  182. </div>
  183. </template>
  184. <style lang="scss" scoped>
  185. .layout-wrap {
  186. width: 100%;
  187. height: 100%;
  188. background-color: #fff;
  189. position: relative;
  190. }
  191. .el-main {
  192. max-width: 1800px;
  193. background-color: #fff;
  194. padding-left: 60px;
  195. padding-top: 0;
  196. margin-left: auto;
  197. margin-right: auto;
  198. position: relative;
  199. .back-icon{
  200. position: fixed;
  201. left: 180px;
  202. top: 23px;
  203. width: 30px;
  204. height: 30px;
  205. cursor: pointer;
  206. }
  207. }
  208. .userinfo-wrap {
  209. background-color: #fff;
  210. width: 186px;
  211. padding: 20px;
  212. text-align: center;
  213. flex-shrink: 0;
  214. .icon-scan {
  215. width: 26px;
  216. height: 26px;
  217. position: relative;
  218. margin-right: 20px;
  219. top: -10px;
  220. }
  221. }
  222. .userinfo-box {
  223. .top {
  224. text-align: center;
  225. margin-bottom: 31px;
  226. p {
  227. margin: 0;
  228. }
  229. }
  230. .info-item {
  231. padding: 20px 26px 20px 20px;
  232. border-top: 1px solid #ebebeb;
  233. position: relative;
  234. .label {
  235. width: 90px;
  236. margin-right: 19px;
  237. flex-shrink: 0;
  238. }
  239. .con{
  240. .btn{
  241. width: 97px;
  242. height: 30px;
  243. border-radius: 8px;
  244. border: 1px solid #DAB37C;
  245. font-size: 16px;
  246. color: #DAB37C;
  247. display: inline-block;
  248. text-align: center;
  249. line-height: 30px;
  250. position: absolute;
  251. right: 0;
  252. top: 50%;
  253. transform: translateY(-50%);
  254. cursor: pointer;
  255. }
  256. }
  257. }
  258. }
  259. .global-audio-box{
  260. position: fixed;
  261. width: 485px;
  262. height: 150px;
  263. background: #FFFFFF;
  264. box-shadow: 0px 3px 12px 0px rgba(81, 88, 101, 0.16);
  265. border-radius: 8px;
  266. border: 1px solid #EBEBEB;
  267. left: 50%;
  268. bottom: 30px;
  269. transform: translateX(-50%);
  270. z-index: 999;
  271. .icon{
  272. float: right;
  273. position: relative;
  274. right: 10px;
  275. cursor: pointer;
  276. }
  277. audio{
  278. width: 90%;
  279. height: 30px;
  280. display: block;
  281. margin-left: auto;
  282. margin-right: auto;
  283. margin-top: 9px;
  284. }
  285. }
  286. </style>