team.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. <template>
  2. <view class="team-page">
  3. <u-navbar title="我的队伍" :autoBack="true" :bgColor="bgColor" leftIconColor="#333"
  4. titleStyle="font-weight:bold;"></u-navbar>
  5. <image class="bg_dance" src="/static/images/enter/activity/bg_dance.png" mode=""></image>
  6. <view class="team-card u-f u-f-ac">
  7. <view class="team-logo u-f-ajc es-mr-30">
  8. <image :src="teamInfo.coverUrl || '/static/images/enter/activity/icon_team.png'" class="" mode="">
  9. </image>
  10. </view>
  11. <view class="team-info">
  12. <view class="team-name">{{teamInfo.teamName || ''}}</view>
  13. <view class="tags u-f u-f-ac">
  14. <view class="tag city">{{teamInfo.city || ''}}</view>
  15. <view class="tag count">{{teamInfo.memberCount || 0}}人</view>
  16. </view>
  17. <view class="captain-info">领队:{{teamInfo.leaderName || ''}}({{teamInfo.leaderPhone || ''}})</view>
  18. <view class="team-code u-f u-f-ac" @click="copyCode">
  19. <text class="es-mr-12">队伍码:{{teamInfo.teamCode || ''}}</text>
  20. <image class="es-icon-32" src="/static/images/enter/activity/icon_copy.png" mode=""></image>
  21. </view>
  22. </view>
  23. </view>
  24. <view class="content-box es-mt-16">
  25. <view class="tabs u-f-ajc ">
  26. <view v-for="(tab, index) in tabs" :key="index" class="tab-item u-f-ajc"
  27. :class="{active: currentTab === index}" @click="switchTab(index)">
  28. {{tab.name}}<text v-if="tab.count">·{{tab.count}}</text>
  29. <view class="line" v-if="currentTab === index"></view>
  30. </view>
  31. </view>
  32. <!-- <mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback"
  33. :down="downOption" :up="upOption"> -->
  34. <!-- Works List -->
  35. <view v-if="currentTab === 0" class="work-list">
  36. <view class="work-item" v-for="(item, index) in workList" :key="index">
  37. <image @tap="videoShow=true" v-if="!videoShow" :src="item.coverUrl" mode="aspectFill"
  38. class="work-cover"></image>
  39. <video v-else :src="item.videoUrl" class="work-cover" object-fit="cover"
  40. :show-center-play-btn="false"></video>
  41. <view class="work-info">
  42. <view class="work-title ellipsis">{{item.workName}}</view>
  43. <view class="u-f u-f-jsb u-f-ac">
  44. <view class="vote-num">票数:{{item.voteCount}}</view>
  45. <view class="delete-btn u-f u-f-ac" @click="handleDeleteWork(item)">
  46. <u-icon name="edit-pen" color="#999" size="18"></u-icon>
  47. <text>修改</text>
  48. </view>
  49. </view>
  50. </view>
  51. </view>
  52. </view>
  53. <!-- Members List -->
  54. <view v-if="currentTab === 1" class="member-list">
  55. <view class="member-item u-f u-f-jsb u-f-ac" v-for="(item, index) in memberList" :key="index">
  56. <view class="member-info u-f u-f-ac">
  57. <image :src="item.avatar || '/static/images/detault_head.jpg'" class="avatar" mode="aspectFill">
  58. </image>
  59. <view class="name">{{item.userName}}</view>
  60. <view class="captain-tag" v-if="teamInfo.leaderId == item.userId">领队</view>
  61. </view>
  62. <view class="remove-btn u-f u-f-ac"
  63. v-if="(teamInfo.leaderId == userId && item.userId != userId) || (item.userId == userId && teamInfo.leaderId != userId)"
  64. @click="handleRemoveMember(item)">
  65. <u-icon name="minus-circle" color="#FF4D4F" size="18"></u-icon>
  66. <text>移出</text>
  67. </view>
  68. </view>
  69. </view>
  70. <!-- </mescroll-body> -->
  71. </view>
  72. <!-- Bottom Buttons -->
  73. <view class="bottom-fixed" v-if="teamInfo.leaderId == userId">
  74. <view v-if="currentTab === 0" class="btn primary-btn"
  75. @click="$navTo(`/pages_enter/activity/publishWork?teamId=${teamInfo.id || ''}`)">
  76. <u-icon name="plus-circle" color="#fff" size="20" class="btn-icon"></u-icon>
  77. 发布作品
  78. </view>
  79. <view v-if="currentTab === 1" class="btn outline-btn" @click="handleDisband()">
  80. 解散队伍
  81. </view>
  82. </view>
  83. </view>
  84. </template>
  85. <script>
  86. import {
  87. deleteTeamMember,
  88. getUserTeam,
  89. getWorkList,
  90. getUserTeamMember
  91. } from '@/api/activity.js';
  92. import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
  93. export default {
  94. mixins: [MescrollMixin],
  95. data() {
  96. return {
  97. videoShow: false,
  98. bgColor: 'transparent',
  99. teamInfo: {},
  100. tabs: [{
  101. name: '作品',
  102. count: 0
  103. },
  104. {
  105. name: '成员',
  106. count: 26
  107. }
  108. ],
  109. currentTab: 0,
  110. workList: [],
  111. memberList: [],
  112. downOption: {
  113. use: true,
  114. auto: false
  115. },
  116. upOption: {
  117. auto: true,
  118. page: {
  119. num: 0,
  120. size: 100
  121. },
  122. onScroll: false,
  123. use: true,
  124. noMoreSize: 10,
  125. textNoMore: "已经到底了",
  126. empty: {
  127. icon: 'https://zkzh-2025.oss-cn-beijing.aliyuncs.com/fs/20240423/cf4a86b913a04341bb44e34bb4d37aa2.png',
  128. tip: '暂无数据'
  129. }
  130. },
  131. userId: null,
  132. teamId: null
  133. }
  134. },
  135. onLoad() {
  136. this.userId = JSON.parse(uni.getStorageSync('userInfo')).userId
  137. },
  138. onPageScroll(e) {
  139. if (e.scrollTop > 20) {
  140. this.bgColor = '#ffefef'
  141. } else {
  142. this.bgColor = 'transparent'
  143. }
  144. },
  145. onShow() {
  146. this.fetchDetail();
  147. },
  148. methods: {
  149. async deleteTeamMemberFun() {
  150. const res = await deleteTeamMember({
  151. activityId: this.teamInfo.id
  152. })
  153. if (res.code == 200) {} else {
  154. uni.showToast({
  155. icon: 'none',
  156. title: res.msg
  157. })
  158. }
  159. },
  160. async fetchDetail() {
  161. const res = await getUserTeam({
  162. activityId: getApp().globalData.activityId
  163. })
  164. if (res.code == 200) {
  165. this.teamInfo = res.team
  166. this.tabs[1].count = this.teamInfo.memberCount || 0
  167. this.teamId = res.team.id
  168. this.getUserTeamMemberFun(res.team.id)
  169. this.getWorkListFun(res.team.id)
  170. } else {
  171. uni.showToast({
  172. icon: 'none',
  173. title: res.msg
  174. })
  175. }
  176. },
  177. async getUserTeamMemberFun(id) {
  178. const res = await getUserTeamMember({
  179. activityId: this.teamInfo.id,
  180. teamId: id
  181. })
  182. if (res.code == 200) {
  183. this.memberList = res.data
  184. } else {
  185. uni.showToast({
  186. icon: 'none',
  187. title: res.msg
  188. })
  189. }
  190. },
  191. async getWorkListFun(id) {
  192. const res = await getWorkList({
  193. activityId: this.teamInfo.id,
  194. teamId: id
  195. })
  196. if (res.code == 200) {
  197. this.workList = res.data.list
  198. } else {
  199. uni.showToast({
  200. icon: 'none',
  201. title: res.msg
  202. })
  203. }
  204. },
  205. copyCode() {
  206. uni.setClipboardData({
  207. data: this.teamInfo.teamCode,
  208. success: () => {
  209. uni.showToast({
  210. title: '复制成功',
  211. icon: 'success'
  212. });
  213. }
  214. });
  215. },
  216. switchTab(index) {
  217. this.currentTab = index;
  218. this.mescroll.resetUpScroll();
  219. },
  220. async upCallback(page) {
  221. return
  222. if (this.currentTab === 0) {
  223. const res = await getUserTeamMember({
  224. pageNum: page.num,
  225. pageSize: page.size,
  226. activityId: getApp().globalData.activityId,
  227. })
  228. if (res.code === 200) {
  229. let curList = res.data.list || [];
  230. if (page.num === 1) this.workList = [];
  231. this.workList = this.workList.concat(curList);
  232. this.mescroll.endBySize(this.memberList.length, res.data.total);
  233. } else {
  234. this.mescroll.endErr();
  235. }
  236. }
  237. },
  238. handleDeleteWork(item) {
  239. uni.navigateTo({
  240. url: `/pages_enter/activity/publishWork?id=${item.id}&teamId=${this.teamInfo.id || ''}`
  241. })
  242. return
  243. uni.showModal({
  244. title: '确认删除',
  245. content: '确认删除该作品吗?',
  246. success: (res) => {
  247. if (res.confirm) {
  248. deleteWork({
  249. workId: item.id
  250. }).then(res => {
  251. if (res.code === 200) {
  252. uni.showToast({
  253. title: '删除成功',
  254. icon: 'success'
  255. });
  256. this.mescroll.resetUpScroll();
  257. }
  258. });
  259. }
  260. }
  261. });
  262. },
  263. handleRemoveMember(item) {
  264. uni.showModal({
  265. title: '确认移出',
  266. content: `确认将 ${item.userName} 移出队伍吗?`,
  267. success: (res) => {
  268. if (res.confirm) {
  269. deleteTeamMember({
  270. activityId: this.teamInfo.id,
  271. teamId: this.teamInfo.id,
  272. deleteUserId: item.userId
  273. }).then(res => {
  274. if (res.code === 200) {
  275. this.getUserTeamMemberFun(this.teamId)
  276. uni.showToast({
  277. title: '移出成功',
  278. icon: 'success'
  279. });
  280. } else {
  281. uni.showToast({
  282. title: res.msg,
  283. icon: 'none'
  284. })
  285. }
  286. });
  287. }
  288. }
  289. });
  290. },
  291. handleDisband() {
  292. uni.showModal({
  293. title: '确认解散',
  294. content: '解散后队伍信息将无法找回,确认解散吗?',
  295. success: (res) => {
  296. if (res.confirm) {
  297. deleteTeamMember({
  298. activityId: this.teamInfo.id,
  299. teamId: this.teamInfo.id,
  300. deleteUserId: this.teamInfo.leaderId
  301. }).then(res => {
  302. if (res.code === 200) {
  303. uni.showToast({
  304. title: '已解散',
  305. icon: 'success'
  306. });
  307. setTimeout(() => {
  308. uni.redirectTo({
  309. url: '/pages_enter/activity/index'
  310. })
  311. }, 1500);
  312. } else {
  313. uni.showToast({
  314. title: res.msg,
  315. icon: 'none'
  316. })
  317. }
  318. });
  319. }
  320. }
  321. });
  322. }
  323. }
  324. }
  325. </script>
  326. <style lang="scss" scoped>
  327. .team-page {
  328. min-height: 100vh;
  329. background-color: #f8f8f8;
  330. padding-top: 120rpx;
  331. box-sizing: border-box;
  332. position: relative;
  333. }
  334. .bg_dance {
  335. width: 100%;
  336. position: absolute;
  337. top: 0;
  338. left: 0;
  339. z-index: 0;
  340. height: 304rpx;
  341. }
  342. .team-card {
  343. position: relative;
  344. z-index: 1;
  345. width: 100vw;
  346. background: #fff;
  347. padding: 40rpx 30rpx;
  348. border-radius: 32rpx;
  349. .team-logo {
  350. width: 152rpx;
  351. height: 152rpx;
  352. border-radius: 24rpx;
  353. background: #FFF5F2;
  354. image {
  355. width: 88rpx;
  356. height: 88rpx;
  357. border-radius: 20rpx;
  358. }
  359. }
  360. .team-info {
  361. flex: 1;
  362. .team-name {
  363. font-size: 36rpx;
  364. font-weight: bold;
  365. color: #333;
  366. margin-bottom: 16rpx;
  367. }
  368. .tags {
  369. margin-bottom: 16rpx;
  370. .tag {
  371. font-size: 22rpx;
  372. padding: 4rpx 16rpx;
  373. border-radius: 6rpx;
  374. margin-right: 16rpx;
  375. &.city {
  376. background: #FFF0F0;
  377. color: #A33C3C;
  378. }
  379. &.count {
  380. background: #FFF0F0;
  381. color: #A33C3C;
  382. }
  383. }
  384. }
  385. .captain-info {
  386. font-size: 24rpx;
  387. color: #999;
  388. margin-bottom: 10rpx;
  389. }
  390. .team-code {
  391. font-size: 24rpx;
  392. color: #999;
  393. .copy-icon {
  394. margin-left: 10rpx;
  395. }
  396. }
  397. }
  398. }
  399. .content-box {
  400. background-color: #fff;
  401. padding: 30rpx;
  402. min-height: calc(100vh - 360rpx);
  403. padding-bottom: 140rpx;
  404. .tabs {
  405. margin-bottom: 30rpx;
  406. justify-content: space-around;
  407. .tab-item {
  408. font-size: 32rpx;
  409. color: #666;
  410. position: relative;
  411. padding-bottom: 16rpx;
  412. margin-right: 60rpx;
  413. &.active {
  414. color: #333;
  415. font-weight: bold;
  416. }
  417. .line {
  418. position: absolute;
  419. bottom: 0;
  420. left: 50%;
  421. transform: translateX(-50%);
  422. width: 40rpx;
  423. height: 6rpx;
  424. background-color: #FF4500;
  425. border-radius: 4rpx;
  426. }
  427. }
  428. }
  429. }
  430. .work-list {
  431. .work-item {
  432. background-color: #fff;
  433. border-radius: 20rpx;
  434. overflow: hidden;
  435. box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
  436. margin-bottom: 30rpx;
  437. .work-cover {
  438. width: 100%;
  439. height: 360rpx;
  440. background-color: #eee;
  441. }
  442. .work-info {
  443. padding: 24rpx;
  444. .work-title {
  445. font-size: 32rpx;
  446. font-weight: bold;
  447. color: #333;
  448. margin-bottom: 24rpx;
  449. }
  450. .vote-num {
  451. font-size: 26rpx;
  452. color: #999;
  453. }
  454. .delete-btn {
  455. color: #999;
  456. font-size: 26rpx;
  457. text {
  458. margin-left: 8rpx;
  459. }
  460. }
  461. }
  462. }
  463. }
  464. .member-list {
  465. .member-item {
  466. padding: 30rpx 0;
  467. border-bottom: 2rpx solid #f0f0f0;
  468. &:last-child {
  469. border-bottom: none;
  470. }
  471. .avatar {
  472. width: 90rpx;
  473. height: 90rpx;
  474. border-radius: 50%;
  475. margin-right: 24rpx;
  476. background-color: #eee;
  477. }
  478. .name {
  479. font-size: 30rpx;
  480. color: #333;
  481. }
  482. .captain-tag {
  483. font-size: 20rpx;
  484. background-color: #FFB35B;
  485. color: #fff;
  486. padding: 2rpx 12rpx;
  487. border-radius: 8rpx;
  488. margin-left: 20rpx;
  489. }
  490. .remove-btn {
  491. color: #FF4D4F;
  492. font-size: 28rpx;
  493. text {
  494. margin-left: 8rpx;
  495. }
  496. }
  497. }
  498. }
  499. .bottom-fixed {
  500. position: fixed;
  501. bottom: 0;
  502. left: 0;
  503. right: 0;
  504. background-color: #fff;
  505. padding: 20rpx 40rpx calc(20rpx + env(safe-area-inset-bottom));
  506. box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.05);
  507. z-index: 10;
  508. .btn {
  509. height: 90rpx;
  510. border-radius: 45rpx;
  511. display: flex;
  512. align-items: center;
  513. justify-content: center;
  514. font-size: 30rpx;
  515. font-weight: 500;
  516. &.primary-btn {
  517. background: linear-gradient(90deg, #FF7F50, #FF1493);
  518. color: #fff;
  519. box-shadow: 0 4rpx 12rpx rgba(255, 20, 147, 0.3);
  520. .btn-icon {
  521. margin-right: 12rpx;
  522. }
  523. }
  524. &.outline-btn {
  525. border: 2rpx solid #FF4D4F;
  526. color: #FF4D4F;
  527. }
  528. &:active {
  529. opacity: 0.8;
  530. }
  531. }
  532. }
  533. </style>