index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. <template>
  2. <view class="container main">
  3. <view class="info">
  4. <scroll-view scroll-y="true" class="scroll-view">
  5. <view class="list-scroll-view">
  6. <view class="one">
  7. <image class="image" :src="getUrl(info.file)"></image>
  8. </view>
  9. <view class="two">
  10. <view class="two_1 name">{{info.name||'暂无活动名称'}}</view>
  11. <view class="two_1 text_color">
  12. <text class="t-icon t-icon-shizhong"></text>
  13. <span>{{getTime(info.start_time,info.end_time)||'暂无'}}</span>
  14. </view>
  15. <view class="two_1 text_color">
  16. <text class="t-icon t-icon-gonglve"></text>
  17. <span>{{getDict(info.match_type,'type')||'自办'}}</span>
  18. </view>
  19. <view class="two_1 text_color">
  20. <text class="t-icon t-icon-gongsi"></text>
  21. <span>{{info.work||'暂无组织单位'}}</span>
  22. </view>
  23. </view>
  24. <view class="thr">
  25. <view class="thr_cont" v-if="info.rules&&info.rules.rules1">
  26. <view class="thr_1">大赛背景</view>
  27. <view class="thr_2">
  28. <rich-text :nodes="formatRichText(info.rules.rules1)"></rich-text>
  29. </view>
  30. </view>
  31. <view class="thr_cont" v-if="info.rules&&info.rules.rules2">
  32. <view class="thr_1">大赛主题和目标</view>
  33. <view class="thr_2">
  34. <rich-text :nodes="formatRichText(info.rules.rules2)"></rich-text>
  35. </view>
  36. </view>
  37. <view class="thr_cont" v-if="info.rules&&info.rules.rules3">
  38. <view class="thr_1">大赛基本情况介绍</view>
  39. <view class="thr_2">
  40. <rich-text :nodes="formatRichText(info.rules.rules3)"></rich-text>
  41. </view>
  42. </view>
  43. <view class="thr_cont" v-if="info.rules&&info.rules.rules4">
  44. <view class="thr_1">赛题任务</view>
  45. <view class="thr_2">
  46. <rich-text :nodes="formatRichText(info.rules.rules4)"></rich-text>
  47. </view>
  48. </view>
  49. <view class="thr_cont" v-if="info.rules&&info.rules.rules5">
  50. <view class="thr_1">赛程安排</view>
  51. <view class="thr_2">
  52. <rich-text :nodes="formatRichText(info.rules.rules5)"></rich-text>
  53. </view>
  54. </view>
  55. <view class="thr_cont" v-if="info.rules&&info.rules.rules6">
  56. <view class="thr_1">赛制阶段</view>
  57. <view class="thr_2">
  58. <rich-text :nodes="formatRichText(info.rules.rules6)"></rich-text>
  59. </view>
  60. </view>
  61. <view class="thr_cont" v-if="info.rules&&info.rules.rules7">
  62. <view class="thr_1">参赛资格</view>
  63. <view class="thr_2">
  64. <rich-text :nodes="formatRichText(info.rules.rules7)"></rich-text>
  65. </view>
  66. </view>
  67. <view class="thr_cont" v-if="info.rules&&info.rules.rules8">
  68. <view class="thr_1">参赛报名</view>
  69. <view class="thr_2">
  70. <rich-text :nodes="formatRichText(info.rules.rules8)"></rich-text>
  71. </view>
  72. </view>
  73. <view class="thr_cont" v-if="info.rules&&info.rules.rules9">
  74. <view class="thr_1">奖项设置与奖励办法</view>
  75. <view class="thr_2">
  76. <rich-text :nodes="formatRichText(info.rules.rules9)"></rich-text>
  77. </view>
  78. </view>
  79. <view class="thr_cont" v-if="info.rules&&info.rules.rules10">
  80. <view class="thr_1">组织单位</view>
  81. <view class="thr_2">
  82. <rich-text :nodes="formatRichText(info.rules.rules10)"></rich-text>
  83. </view>
  84. </view>
  85. <view class="thr_cont" v-if="info.rules&&info.rules.rules11">
  86. <view class="thr_1">赛事联络</view>
  87. <view class="thr_2">
  88. <rich-text :nodes="formatRichText(info.rules.rules11)"></rich-text>
  89. </view>
  90. </view>
  91. <view class="thr_cont" v-if="info.rules&&info.rules.rules12">
  92. <view class="thr_1">赛事交流</view>
  93. <view class="thr_2">
  94. <rich-text :nodes="formatRichText(info.rules.rules12)"></rich-text>
  95. </view>
  96. </view>
  97. </view>
  98. <view class="thr" v-if="info.brief">
  99. <view class="thr_cont">
  100. <view class="thr_1">常见问题</view>
  101. <view class="thr_2">
  102. <rich-text :nodes="formatRichText(info.brief)"></rich-text>
  103. </view>
  104. </view>
  105. </view>
  106. <view class="thr" v-if="info.form == '3'&&info.match_status == '3' && signList.length > 0">
  107. <view class="thr_cont">
  108. <uni-section title="参演方信息" type="line">
  109. <uni-group mode="card" v-for="(item, index) in signList" :key="index">
  110. <view class="card_title" style="font-weight: bold;">{{ item.name || '暂无' }} </view>
  111. <view class="card_title"> <span>路演名称:</span>{{ item.project_name || '暂无' }} </view>
  112. <view class="card_title"> <span>路演介绍:</span>{{ item.project_brief || '暂无' }} </view>
  113. <view class="card_title" v-if="info.is_show == '0'">
  114. <span>联系方式:</span>{{ item.phone || '暂无' }}
  115. </view>
  116. <view class="card_button" v-else style="text-align: center;margin: 10px 0 0 0;">
  117. <button class="button" size="mini" type="primary"
  118. @tap.stop="toChat(item)">获取联系方式</button>
  119. </view>
  120. </uni-group>
  121. </uni-section>
  122. </view>
  123. </view>
  124. <view class="thr" v-if="info.form == '4' && info.ext_status == '3'">
  125. <view class="thr_cont">
  126. <uni-section title="初审公示名单" type="line">
  127. <uni-group mode="card" v-for="(item, index) in preliminaryList" :key="index">
  128. <view class="card_title" style="font-weight: bold;">
  129. {{ item.user_name || '暂无' }}
  130. </view>
  131. <view class="card_title">
  132. <span>编号:</span>{{ item.no || '暂无' }}
  133. </view>
  134. <view class="card_title">
  135. <span>项目名称:</span>{{ item.project_name || '暂无' }}
  136. </view>
  137. <view class="card_title">
  138. <span>单位名称:</span>{{ item.person_unit || '暂无' }}
  139. </view>
  140. <view class="card_title">
  141. <span>初审时间:</span>{{ item.start_time || '暂无' }}
  142. </view>
  143. </uni-group>
  144. </uni-section>
  145. </view>
  146. </view>
  147. <view class="thr" v-if="info.form == '4' && info.ext_status == '6'">
  148. <view class="thr_cont">
  149. <uni-section title="决赛公示名单" type="line">
  150. <uni-group mode="card" v-for="(item, index) in finalsList" :key="index">
  151. <view class="card_title" style="font-weight: bold;">
  152. {{ item.user_name || '暂无' }}
  153. </view>
  154. <view class="card_title">
  155. <span>编号:</span>{{ item.no || '暂无' }}
  156. </view>
  157. <view class="card_title">
  158. <span>项目名称:</span>{{ item.project_name || '暂无' }}
  159. </view>
  160. <view class="card_title">
  161. <span>单位名称:</span>{{ item.person_unit || '暂无' }}
  162. </view>
  163. <view class="card_title">
  164. <span>初审时间:</span>{{ item.start_time || '暂无' }}
  165. </view>
  166. <view class="card_title">
  167. <span>决赛时间:</span>{{ item.final_start_time || '暂无' }}
  168. </view>
  169. <view class="card_title">
  170. <span>顺序:</span>{{ item.final_order_no || '暂无' }}
  171. </view>
  172. </uni-group>
  173. </uni-section>
  174. </view>
  175. </view>
  176. </view>
  177. </scroll-view>
  178. </view>
  179. <view class="foot">
  180. <view class="foot_text foot_1" @tap="toFriend()">分享给好友</view>
  181. <view class="foot_text foot_2" @tap="toSign()">报名活动</view>
  182. </view>
  183. <uni-popup ref="share" type="share" safeArea backgroundColor="#fff">
  184. <view class="popup_cont">
  185. <view class="popup_title">
  186. <text>分享到</text>
  187. </view>
  188. <view class="popup_share">
  189. <view class="share_1">
  190. <button type="primary" plain="true" open-type="share" @click="toShare">
  191. <text class="t-icon t-icon-weixin"></text>
  192. <text>分享给好友</text>
  193. </button>
  194. </view>
  195. <view class="share_1">
  196. <button type="primary" plain="true" open-type="share" @click="toPoster">
  197. <text class="t-icon t-icon-iconfontzhizuobiaozhunbduan36"></text>
  198. <text>生成活动海报</text>
  199. </button>
  200. </view>
  201. </view>
  202. </view>
  203. </uni-popup>
  204. </view>
  205. </template>
  206. <script>
  207. export default {
  208. data() {
  209. return {
  210. id: '',
  211. user: {},
  212. config: {},
  213. info: {},
  214. // 字典表
  215. statusList: [],
  216. typeList: [],
  217. // 参演方
  218. signList: [],
  219. // 初审结果公示
  220. preliminaryList: [],
  221. // 决赛结果公示
  222. finalsList: [],
  223. }
  224. },
  225. onLoad: async function(e) {
  226. const that = this;
  227. that.$set(that, `id`, e && e.id || '');
  228. that.searchConfig();
  229. await that.searchOther();
  230. await that.search();
  231. },
  232. onShow: async function() {
  233. const that = this;
  234. that.searchToken();
  235. },
  236. onUnload: function() {
  237. // 页面卸载,重新部署分享内容
  238. const that = this;
  239. if (that.config) {
  240. // 赋值默认值
  241. that.$config.share = {
  242. title: that.config.zhTitle,
  243. path: '/pages/index/index',
  244. imageUrl: that.config?.logoUrl[0]?.url
  245. }
  246. }
  247. },
  248. methods: {
  249. // 用户信息
  250. searchToken() {
  251. const that = this;
  252. try {
  253. const res = uni.getStorageSync('token');
  254. if (res) {
  255. const user = that.$jwt(res);
  256. that.$set(that, `user`, user);
  257. }
  258. } catch (e) {}
  259. },
  260. searchConfig() {
  261. const that = this;
  262. try {
  263. const res = uni.getStorageSync('config');
  264. if (res) that.$set(that, `config`, res);
  265. } catch (e) {}
  266. },
  267. // 查询其他信息
  268. async searchOther() {
  269. const that = this;
  270. let res;
  271. // 查询类型
  272. res = await that.$api(`/dictData`, 'GET', {
  273. code: 'matchStatus',
  274. is_use: '0',
  275. })
  276. if (res.errcode == '0') that.$set(that, `statusList`, res.data);
  277. // 赛事类型
  278. res = await that.$api(`/dictData`, 'GET', {
  279. code: 'activeType',
  280. is_use: '0',
  281. })
  282. if (res.errcode == '0') that.$set(that, `typeList`, res.data)
  283. },
  284. // 查询
  285. async search() {
  286. const that = this;
  287. if (that.id) {
  288. let res;
  289. res = await that.$api(`/match/${that.id}`, 'GET', {})
  290. if (res.errcode == '0') {
  291. that.$set(that, `info`, res.data)
  292. if (res.data.form == '3') {
  293. const arr = await that.$api(`/sign`, 'GET', {
  294. match: res.data.id,
  295. status: '1',
  296. type: '1'
  297. })
  298. if (arr.errcode == '0') that.$set(that, `signList`, arr.data)
  299. }
  300. if (res.data.form == '4' && res.data.ext_status == '3') {
  301. await that.searchStep3()
  302. }
  303. if (res.data.form == '4' && res.data.ext_status == '6') {
  304. await that.searchStep5()
  305. }
  306. } else {
  307. uni.showToast({
  308. title: res.errmsg,
  309. });
  310. }
  311. }
  312. },
  313. // 查询初审公示名单
  314. async searchStep3() {
  315. const that = this;
  316. const res = await that.$api(`/matchExt/step3/nameList/${that.id}`, 'GET', {})
  317. if (res.errcode == '0') that.$set(that, `preliminaryList`, res.data)
  318. },
  319. // 查询决赛公示名单
  320. async searchStep5() {
  321. const that = this;
  322. const res = await that.$api(`/matchExt/step5/list/${that.id}`, 'GET', {
  323. final_confirm: '0'
  324. })
  325. if (res.errcode == '0') that.$set(that, `finalsList`, res.data)
  326. },
  327. // 处理时间
  328. getTime(start_time, end_time) {
  329. if (start_time && end_time) {
  330. const start = new Date(start_time);
  331. const end = new Date(end_time);
  332. const weekdays = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
  333. const day = start.getDate();
  334. const weekday = weekdays[start.getDay()];
  335. const year = start.getFullYear();
  336. const month = start.getMonth();
  337. const start_hours = start.getHours();
  338. const start_minutes = start.getMinutes();
  339. const end_hours = end.getHours();
  340. const end_minutes = end.getMinutes();
  341. return `${year}/${month+1}/${day < 10 ? '0' + day : day} ${weekday} ${start_hours.toString().padStart(2, '0')}:${start_minutes.toString().padStart(2, '0')} - ${end_hours.toString().padStart(2, '0')}:${end_minutes.toString().padStart(2, '0')} `;
  342. }
  343. },
  344. // 处理字典表
  345. getDict(item, model) {
  346. const that = this;
  347. let res
  348. if (model == 'type') res = that.typeList.find(i => i.value == item)
  349. if (res) return res.label
  350. else return '暂无'
  351. },
  352. // 图片处理
  353. getUrl(e) {
  354. const that = this;
  355. if (e && e.length > 0) return that.$config.serverFile + e[0].url
  356. else return '/static/match.png'
  357. },
  358. // 处理富文本
  359. formatRichText(html) {
  360. if (html) {
  361. html = html.replace(/<table[^>]*>/gi, match => {
  362. // 如果已有 style 属性,替换为新的样式;如果没有,添加新的 style 属性
  363. return match.replace(/style="[^"]+"/gi,
  364. `style="border-collapse: collapse; width: 100%;text-align: center;"`)
  365. .replace(/<table/gi,
  366. `<table style="border-collapse: collapse; width: 100%;text-align: center;"`);
  367. });
  368. html = html.replace(/<th[^>]*>/gi, match => {
  369. // 如果已有 style 属性,替换为新的样式;如果没有,添加新的 style 属性
  370. return match.replace(/style="[^"]+"/gi,
  371. `style="border: 1px solid #ddd; padding: 8px; background-color: #f2f2f2;text-align: center;"`
  372. )
  373. .replace(/<table/gi,
  374. `<table style="border: 1px solid #ddd; padding: 8px; background-color: #f2f2f2;text-align: center;"`
  375. );
  376. });
  377. html = html.replace(/<td[^>]*>/gi, match => {
  378. // 如果已有 style 属性,替换为新的样式;如果没有,添加新的 style 属性
  379. return match.replace(/style="[^"]+"/gi,
  380. `style="border: 1px solid #ddd; padding: 8px;text-align: center;"`)
  381. .replace(/<table/gi,
  382. `<table style="border: 1px solid #ddd; padding: 8px;text-align: center;"`);
  383. });
  384. // 富文本内容格式化
  385. return html && html.replace(/<img[^>]*>/gi, function(match, capture) {
  386. // 查找所有的 img 元素
  387. return match.replace(/style=".*"/gi, '').replace(/style='.*'/gi,
  388. '')
  389. // 删除找到的所有 img 元素中的 style 属性
  390. }).replace(/\<img/gi, '<img style="width:100%;"') // 对 img 元素增加 style 属性,并设置宽度为 100%
  391. }
  392. },
  393. // 分享给好友
  394. toFriend() {
  395. const that = this;
  396. that.$refs.share.open()
  397. },
  398. // 活动报名
  399. toSign() {
  400. const that = this;
  401. if (that.info.match_status == '0') {
  402. uni.showToast({
  403. title: '活动未开始 暂不支持报名!',
  404. icon: 'none'
  405. })
  406. } else if (that.info.match_status == '1') {
  407. if (that.user && that.user.id) {
  408. if (that.info.form == '3') {
  409. uni.navigateTo({
  410. url: `/pagesHome/match/active?id=${that.id}`
  411. })
  412. } else if (that.info.form == '4') {
  413. uni.navigateTo({
  414. url: `/pagesHome/investigate/index?id=${that.id}`
  415. })
  416. } else {
  417. uni.navigateTo({
  418. url: `/pagesHome/match/sign?id=${that.id}`
  419. })
  420. }
  421. } else {
  422. if (that.info.form == '4') {
  423. uni.navigateTo({
  424. url: `/pagesHome/investigate/index?id=${that.id}`
  425. })
  426. } else {
  427. uni.navigateTo({
  428. url: `/pagesHome/login/index`
  429. })
  430. }
  431. }
  432. } else if (that.info.match_status == '2') {
  433. uni.showToast({
  434. title: '活动进行中 暂不支持报名!',
  435. icon: 'none'
  436. })
  437. } else {
  438. uni.showToast({
  439. title: '比赛已结束!',
  440. icon: 'none'
  441. })
  442. }
  443. },
  444. // 分享给好友
  445. toShare() {
  446. const that = this;
  447. let info = that.info;
  448. let imageUrl = that.config?.logoUrl[0]?.url || info.file[0]?.url;
  449. that.$config.share = {
  450. title: info.name,
  451. path: `/pagesHome/match/index?id=${that.id}`,
  452. imageUrl: imageUrl
  453. }
  454. },
  455. // 生成海报
  456. toPoster() {
  457. console.log('生成海报');
  458. },
  459. // 获取联系方式
  460. toChat(item) {
  461. const that = this;
  462. if (that.user.id) {
  463. uni.showModal({
  464. title: '提示',
  465. content: '您确认要获取联系方式?',
  466. success: async function(res) {
  467. if (res.confirm) {
  468. let source_id = item.id
  469. let source = 'sign'
  470. let apply_user = that.user.id
  471. const res = await that.$api(`/contactApply/sign`, 'POST', {
  472. source_id,
  473. source,
  474. apply_user
  475. })
  476. if (res.errcode == 0) {
  477. uni.showToast({
  478. title: '申请获取联系方式成功,等待发送消息',
  479. icon: 'none'
  480. })
  481. } else {
  482. uni.showToast({
  483. title: res.errmsg,
  484. icon: 'none'
  485. })
  486. }
  487. } else if (res.cancel) {
  488. console.log('用户点击取消');
  489. }
  490. }
  491. });
  492. } else {
  493. uni.navigateTo({
  494. url: `/pagesHome/login/index`
  495. })
  496. }
  497. }
  498. }
  499. }
  500. </script>
  501. <style lang="scss" scoped>
  502. .main {
  503. .info {
  504. position: relative;
  505. flex-grow: 1;
  506. background-color: var(--f9Color);
  507. .one {
  508. .image {
  509. width: 100%;
  510. height: 50vw;
  511. }
  512. }
  513. .two {
  514. padding: 0 2vw;
  515. background-color: var(--mainColor);
  516. .two_1 {
  517. display: flex;
  518. align-items: center;
  519. padding: 3vw 0;
  520. border-bottom: 1px solid var(--f5Color);
  521. font-size: var(--font14Size);
  522. span {
  523. margin: 0 0 0 1vw;
  524. }
  525. .t-icon {
  526. width: var(--font15Size) !important;
  527. height: var(--font15Size) !important;
  528. }
  529. }
  530. .name {
  531. font-weight: bold;
  532. font-size: var(--font16Size);
  533. }
  534. .text_color {
  535. color: var(--f69Color);
  536. }
  537. }
  538. .thr {
  539. margin: 3vw 0 0 0;
  540. background-color: var(--mainColor);
  541. .thr_cont {
  542. margin: 2vw 0 0 0;
  543. .thr_1 {
  544. text-indent: 10px;
  545. border-left: 3px solid var(--f3CColor);
  546. font-weight: bold;
  547. font-size: var(--font16Size);
  548. }
  549. .thr_2 {
  550. padding: 2vw;
  551. }
  552. }
  553. }
  554. }
  555. .foot {
  556. width: 100%;
  557. height: 8vh;
  558. overflow: hidden;
  559. display: flex;
  560. align-items: center;
  561. .foot_text {
  562. display: flex;
  563. justify-content: center;
  564. align-items: center;
  565. width: 50%;
  566. height: 100%;
  567. color: var(--mainColor);
  568. }
  569. .foot_1 {
  570. background: linear-gradient(90deg, #FFCD1E, #FF8A18);
  571. }
  572. .foot_2 {
  573. background: linear-gradient(90deg, #1E83FF, #1071e6);
  574. }
  575. }
  576. .popup_cont {
  577. .popup_title {
  578. display: flex;
  579. flex-direction: row;
  580. align-items: center;
  581. justify-content: center;
  582. height: 40px;
  583. font-size: var(--font14Size);
  584. color: #666;
  585. }
  586. .popup_share {
  587. display: flex;
  588. align-items: center;
  589. padding: 2vw 0;
  590. .share_1 {
  591. width: 50%;
  592. button {
  593. background: none;
  594. border: none;
  595. display: flex;
  596. flex-direction: column;
  597. justify-content: center;
  598. align-items: center;
  599. .t-icon {
  600. width: 8vw;
  601. height: 8vw;
  602. }
  603. text {
  604. margin-top: 10px;
  605. font-size: var(--font14Size);
  606. color: #3B4144;
  607. }
  608. }
  609. }
  610. }
  611. }
  612. }
  613. .scroll-view {
  614. position: absolute;
  615. top: 0;
  616. left: 0;
  617. right: 0;
  618. bottom: 0;
  619. .list-scroll-view {
  620. display: flex;
  621. flex-direction: column;
  622. }
  623. }
  624. </style>