This commit is contained in:
那些花儿
2025-04-30 17:12:04 +08:00
11 changed files with 1013 additions and 17 deletions
@@ -0,0 +1,107 @@
package com.budwk.app.client.module.activity.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DateUtil;
import com.budwk.app.base.page.PageForm;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.client.module.activity.service.ClientDynamicService;
import com.budwk.app.module.activity.models.ActDynamic;
import com.budwk.app.module.activity.models.ActDynamicPraise;
import com.budwk.app.web.commons.auth.satoken.StpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.adaptor.JsonAdaptor;
import org.nutz.mvc.annotation.AdaptBy;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
/**
* @ClassName ClientDynamicController
* @Author JyuHsin
* @Date 2025/4/30 14:16
* @Version 1.0
* @Description TODO
*/
@Slf4j
@IocBean
@Ok("json:full")
@At("/client/activity/dynamic")
public class ClientDynamicController {
@Inject
private ClientDynamicService dynamicService;
@At("/list")
@AdaptBy(type = JsonAdaptor.class)
@SaCheckLogin(type = StpClientUtil.TYPE)
public Result list(@Param("pageForm") PageForm pageForm, @Param("activityId") Long activityId) {
Sql sql = Sqls.create("""
SELECT
ad.*,
cu.userName,
cu.sex,
(select count(1) from act_dynamic_praise where dynamicId = ad.id) as praiseCount,
(select count(1) from act_dynamic_praise where dynamicId = ad.id and userId = '') as selfPraiseCount
FROM
`act_dynamic` ad
LEFT JOIN client_user cu ON ad.userId = cu.id
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("ad.activityId", "=", activityId);
cnd.desc("ad.publishTime");
sql.setCondition(cnd);
Pagination pagination = dynamicService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
return Result.success(pagination);
}
@At("/onHandle")
@AdaptBy(type = JsonAdaptor.class)
@SaCheckLogin(type = StpClientUtil.TYPE)
public Result onHandle(ActDynamic actDynamic) {
actDynamic.setUserId(StpClientUtil.STP.getLoginIdAsLong());
actDynamic.setPublishTime(DateUtil.now());
dynamicService.insert(actDynamic);
return Result.success();
}
@At("/praise/?")
@SaCheckLogin(type = StpClientUtil.TYPE)
public Result praise(Long id) {
int count = dynamicService.dao().count(
ActDynamicPraise.class,
Cnd.where("dynamicId", "=", id).and("userId", "=", StpClientUtil.STP.getLoginIdAsLong())
);
if(count > 0) {
dynamicService.dao().clear(
ActDynamicPraise.class,
Cnd.where("dynamicId", "=", id).and("userId", "=", StpClientUtil.STP.getLoginIdAsLong())
);
} else {
ActDynamicPraise praise = new ActDynamicPraise();
praise.setUserId(StpClientUtil.STP.getLoginIdAsLong());
praise.setDynamicId(id);
praise.setPraiseTime(DateUtil.now());
dynamicService.dao().insert(praise);
}
return Result.success();
}
@At("/onDelete/?")
@SaCheckLogin(type = StpClientUtil.TYPE)
@Aop(TransAop.READ_COMMITTED)
public Result onDelete(Long id) {
dynamicService.delete(id);
dynamicService.dao().clear(ActDynamicPraise.class, Cnd.where("dynamicId", "=", id));
return Result.success();
}
}
@@ -0,0 +1,14 @@
package com.budwk.app.client.module.activity.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.module.activity.models.ActDynamic;
/**
* @ClassName ActHighLightsService
* @Author JyuHsin
* @Date 2025/4/30 14:17
* @Version 1.0
* @Description TODO
*/
public interface ClientDynamicService extends BaseService<ActDynamic> {
}
@@ -0,0 +1,22 @@
package com.budwk.app.client.module.activity.service.impl;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.client.module.activity.service.ClientDynamicService;
import com.budwk.app.module.activity.models.ActDynamic;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.IocBean;
/**
* @ClassName ActHighLightsServiceImpl
* @Author JyuHsin
* @Date 2025/4/30 14:17
* @Version 1.0
* @Description TODO
*/
@IocBean(args = {"refer:dao"})
public class ClientDynamicServiceImpl extends BaseServiceImpl<ActDynamic> implements ClientDynamicService {
public ClientDynamicServiceImpl(Dao dao) {
super(dao);
}
}
@@ -80,7 +80,7 @@ public class ActivitySignInQueryController {
}
cnd.and("au.activityId", "=", pageForm.getActivityId());
cnd.and("au.isSignIn", "=", 1);
cnd.asc("au.actUserNo");
cnd.desc("au.signInTime");
sql.setCondition(cnd);
Pagination pagination = activitySignInQueryService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
return Result.success(pagination);
@@ -110,7 +110,7 @@ public class ActivitySignInQueryController {
}
cnd.and("au.activityId", "=", pageForm.getActivityId());
cnd.and("au.isSignIn", "=", 1);
cnd.asc("au.actUserNo");
cnd.desc("au.signInTime");
sql.setCondition(cnd);
List<NutMap> nutMaps = activitySignInQueryService.listMap(sql);
List<ExcelExportEntity> entityList = new ArrayList<>() {{
@@ -0,0 +1,54 @@
package com.budwk.app.module.activity.models;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.json.JSONObject;
import org.nutz.dao.entity.annotation.*;
import java.time.LocalDateTime;
import java.util.List;
/**
* @ClassName ActDynamic
* @Author JyuHsin
* @Date 2025/4/30 14:13
* @Version 1.0
* @Description TODO
*/
@Data
@Comment("高光时刻")
@Table("act_dynamic")
@EqualsAndHashCode(callSuper = true)
@TableMeta("{'mysql-charset':'utf8mb4'}")
public class ActDynamic extends BaseModel {
@Id
@Comment("ID")
private Long id;
@Column
@Comment("活动ID")
@ColDefine(customType = "bigint")
private Long activityId;
@Column
@Comment("用户id")
@ColDefine(customType = "bigint")
private Long userId;
@Column
@Comment("发布内容")
@ColDefine(type = ColType.VARCHAR, width = 500)
private String content;
@Comment("发布时间")
@Column
@ColDefine(type = ColType.VARCHAR, width = 30)
private String publishTime;
@Comment("发布图片")
@Column
@ColDefine(type = ColType.MYSQL_JSON)
private List<String> files;
}
@@ -0,0 +1,40 @@
package com.budwk.app.module.activity.models;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
/**
* @ClassName ActDynamicPraise
* @Author JyuHsin
* @Date 2025/4/30 14:27
* @Version 1.0
* @Description TODO
*/
@Data
@Comment("赞")
@Table("act_dynamic_praise")
@EqualsAndHashCode(callSuper = true)
@TableMeta("{'mysql-charset':'utf8mb4'}")
public class ActDynamicPraise extends BaseModel {
@Id
@Comment("ID")
private Long id;
@Column
@Comment("精彩瞬间id")
@ColDefine(customType = "bigint")
private Long dynamicId;
@Column
@Comment("用户id")
@ColDefine(customType = "bigint")
private Long userId;
@Comment("点赞时间")
@Column
@ColDefine(type = ColType.VARCHAR, width = 30)
private String praiseTime;
}
+6
View File
@@ -78,6 +78,12 @@
"style": {
"navigationBarTitleText": "成绩查询"
}
},
{
"path": "pages/activity/dynamic/index",
"style": {
"navigationBarTitleText": "精彩瞬间"
}
}
],
"globalStyle": {
@@ -0,0 +1,477 @@
<template>
<view class="publish-modal" v-if="show">
<view class="modal-mask" @tap="handleClose"></view>
<view class="modal-content">
<view class="modal-header">
<text class="title">发布动态</text>
<text class="close" @tap="handleClose">×</text>
</view>
<view class="modal-body">
<textarea
class="content-input"
v-model="momentData.content"
placeholder="分享你的想法..."
:maxlength="500"
auto-height
:focus="show"
/>
<view class="input-counter">{{ momentData.content.length }}/500</view>
<!-- 图片上传区域 -->
<view class="image-uploader">
<view class="uploader-title">添加图片</view>
<view class="upload-grid">
<!-- 已上传图片 -->
<view
v-for="(image, index) in momentData.images"
:key="index"
class="upload-item"
>
<image class="upload-image" :src="image.path" mode="aspectFill"/>
<view class="remove-icon" @tap.stop="removeImage(index)">×</view>
</view>
<!-- 上传按钮 -->
<view
class="upload-btn"
@tap="chooseImages"
v-if="momentData.images.length < 9"
>
<text class="upload-icon">+</text>
</view>
</view>
</view>
<!-- 位置信息 -->
<!-- <view class="location-selector">-->
<!-- <view class="selector-title">位置信息</view>-->
<!-- <view-->
<!-- v-if="!momentData.location"-->
<!-- class="location-btn"-->
<!-- @tap="chooseLocation"-->
<!-- >-->
<!-- <text class="location-icon">📍</text>-->
<!-- <text class="location-text">添加位置</text>-->
<!-- </view>-->
<!-- <view v-else class="location-info">-->
<!-- <view class="location-name">-->
<!-- <text class="location-icon">📍</text>-->
<!-- <text>{{ momentData.location.name }}</text>-->
<!-- </view>-->
<!-- <view class="location-address">{{ momentData.location.address }}</view>-->
<!-- <text class="clear-location" @tap="clearLocation">×</text>-->
<!-- </view>-->
<!-- </view>-->
</view>
<view class="modal-footer">
<button
class="publish-button"
:class="{ 'button-active': canPublish }"
:disabled="!canPublish"
@tap="publishMoment"
>
发布
</button>
</view>
</view>
</view>
</template>
<script setup>
import { reactive, computed } from 'vue'
import { useRequest } from "@/utils/request"
const request = useRequest()
// 接收 props
const props = defineProps({
show: {
type: Boolean,
default: false
},
actId: {
type: Number,
default: null
}
})
// 定义 emit
const emit = defineEmits(['update:show', 'close', 'published'])
// 动态数据
const momentData = reactive({
content: '',
images: [],
location: null
})
// 计算是否可以发布
const canPublish = computed(() =>
momentData.content.trim().length > 0 || momentData.images.length > 0
)
// 关闭弹窗并重置表单
function handleClose() {
emit('update:show', false)
emit('close')
resetForm()
}
// 重置表单
function resetForm() {
momentData.content = ''
momentData.images = []
momentData.location = null
}
// 选择图片
function chooseImages() {
if (momentData.images.length >= 9) {
uni.showToast({ title: '最多只能上传9张图片', icon: 'none' })
return
}
const count = 9 - momentData.images.length
uni.chooseImage({
count,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
const tempFiles = res.tempFiles
momentData.images.push(...tempFiles)
console.log( momentData.images)
}
})
}
// 删除图片
function removeImage(index) {
momentData.images.splice(index, 1)
}
// 选择位置
function chooseLocation() {
uni.chooseLocation({
success: (res) => {
momentData.location = {
name: res.name,
address: res.address,
latitude: res.latitude,
longitude: res.longitude
}
}
})
}
// 清除位置
function clearLocation() {
momentData.location = null
}
// 发布动态
async function publishMoment() {
if (!canPublish.value) return
try {
uni.showLoading({ title: '发布中...' })
const uploadedImages = []
console.log(momentData.images)
for (const image of momentData.images) {
try {
const uploadResult = await request.upload(image)
if(uploadResult.code === 0) {
uploadedImages.push(uploadResult.data)
}
} catch (uploadError) {
console.error('图片上传失败:', uploadError)
uni.showToast({
title: '图片上传失败: ' + (uploadError.message || '未知错误'),
icon: 'none',
duration: 3000
})
}
}
if (momentData.images.length > 0 && uploadedImages.length === 0) {
throw new Error('所有图片上传失败')
}
const publishData = {
content: momentData.content,
files: uploadedImages,
activityId: props.actId
}
const resp = await request.post('/client/activity/dynamic/onHandle', publishData)
if(resp.code === 0) {
uni.showToast({ title: '发布成功', icon: 'success' })
emit('published')
handleClose()
} else {
throw new Error(resp.msg)
}
} catch (error) {
console.error('发布动态失败:', error)
uni.showToast({ title: error.message || '发布失败,请重试', icon: 'none' })
} finally {
uni.hideLoading()
}
}
</script>
<style scoped lang="less">
.publish-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 200;
.modal-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
}
.modal-content {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: white;
border-radius: 24rpx 24rpx 0 0;
max-height: 90vh;
overflow-y: auto;
animation: slideUpIn 0.3s ease;
.modal-header {
display: flex;
justify-content: center;
align-items: center;
padding: 30rpx;
position: relative;
border-bottom: 1rpx solid #f0f0f0;
.title {
font-size: 34rpx;
font-weight: 600;
color: #333;
}
.close {
position: absolute;
right: 30rpx;
font-size: 40rpx;
color: #999;
}
}
.modal-body {
padding: 30rpx;
.content-input {
width: 100%;
min-height: 200rpx;
font-size: 30rpx;
line-height: 1.5;
color: #333;
padding: 20rpx 0;
}
.input-counter {
text-align: right;
font-size: 24rpx;
color: #999;
margin-bottom: 30rpx;
}
.image-uploader {
margin-bottom: 30rpx;
.uploader-title {
font-size: 28rpx;
color: #666;
margin-bottom: 20rpx;
}
.upload-grid {
display: flex;
flex-wrap: wrap;
margin: 0 -10rpx;
.upload-item, .upload-btn {
width: calc(33.333% - 20rpx);
margin: 10rpx;
position: relative;
}
.upload-item {
aspect-ratio: 1/1;
border-radius: 12rpx;
overflow: hidden;
.upload-image {
width: 100%;
height: 100%;
}
.remove-icon {
position: absolute;
top: 10rpx;
right: 10rpx;
width: 44rpx;
height: 44rpx;
border-radius: 22rpx;
background: rgba(0, 0, 0, 0.5);
color: white;
font-size: 30rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
.upload-btn {
aspect-ratio: 1/1;
border: 2rpx dashed #ddd;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
.upload-icon {
font-size: 60rpx;
color: #ccc;
}
}
}
}
.location-selector {
margin-bottom: 30rpx;
.selector-title {
font-size: 28rpx;
color: #666;
margin-bottom: 20rpx;
}
.location-btn {
display: flex;
align-items: center;
padding: 20rpx 0;
.location-icon {
font-size: 36rpx;
color: #ff5777;
margin-right: 10rpx;
}
.location-text {
font-size: 28rpx;
color: #666;
}
}
.location-info {
background: #f5f5f5;
padding: 20rpx;
border-radius: 12rpx;
position: relative;
.location-name {
display: flex;
align-items: center;
font-size: 28rpx;
font-weight: 500;
color: #333;
margin-bottom: 10rpx;
.location-icon {
font-size: 32rpx;
color: #ff5777;
margin-right: 10rpx;
}
}
.location-address {
font-size: 24rpx;
color: #999;
margin-left: 42rpx;
}
.clear-location {
position: absolute;
top: 10rpx;
right: 10rpx;
width: 44rpx;
height: 44rpx;
border-radius: 22rpx;
background: rgba(0, 0, 0, 0.1);
color: #666;
font-size: 30rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
.modal-footer {
padding: 20rpx 30rpx calc(40rpx + env(safe-area-inset-bottom));
.publish-button {
width: 100%;
height: 90rpx;
border-radius: 45rpx;
background: #f0f0f0;
color: #999;
font-size: 32rpx;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s;
&.button-active {
background: #5c6bc0;
color: white;
}
}
}
}
}
@keyframes slideUpIn {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}
.publish-header {
background: var(--gradient-primary);
.title {
color: #ffffff;
}
.action-button {
color: #ffffff;
font-weight: bold;
}
}
.publish-button {
background: var(--gradient-primary);
color: #ffffff;
}
</style>
@@ -0,0 +1,276 @@
<template>
<view class="page-container">
<t-dropdown-menu class="top-dropdown">
<t-dropdown-item :options="actOptions" :value="selectActId"/>
</t-dropdown-menu>
<scroll-view
scroll-y
class="list-scroll-view"
@scrolltolower="handleScrollToBottom"
refresher-enabled
:refresher-triggered="refresherTriggered"
@refresherrefresh="handleRefresh"
refresher-background="#f2f3f5"
>
<view class="content-container">
<view v-for="item in dataList">
<view class="content-container-header">
<view>
<t-avatar shape="circle" image="https://tdesign.gtimg.com/mobile/demos/avatar1.png" />
</view>
<view style="margin-left: 12px">
<view class="title">{{ item.userName }}</view>
<view class="content">{{ item.sex }}</view>
</view>
</view>
<view class="content-container-text">
{{ item.content }}
</view>
<view class="content-container-pic">
<t-image
v-for="p in JSON.parse(item.files)"
v-if="item.files && item.files?.length > 0"
class="image-container"
:style="{ width: '72px', height: '72px', 'margin-right': '8px'}"
fit="contain"
@click="onView(item.files)"
:src="p"></t-image>
</view>
<view class="content-container-footer">
<view class="time">{{ moment(item.publish).format('MM-DD HH:mm') }}</view>
<view @click="onPraise(item)">
<t-badge :count="item.praiseCount" :offset="[-2, -2]" class="badge-item" :showZero="true">
<t-icon :style="item.praiseCount > 0 ? 'color: red' : ''" name="thumb-up-2-filled"/>
</t-badge>
</view>
</view>
<t-divider />
</view>
</view>
<!-- 加载状态 -->
<view class="loading-container">
<t-loading v-if="loading" text="加载中..." layout="vertical" theme="circular" size="40rpx"/>
<t-divider v-else-if="!hasMore && dataList.length > 0" content="没有更多数据了"/>
</view>
<!-- 空状态 -->
<t-empty
v-if="!loading && dataList.length === 0"
description="暂无精彩瞬间"
/>
</scroll-view>
</view>
<t-fab :icon="iconFunc" draggable="all" :y-bounds="[30, 20]" @click="onClick" />
<t-image-viewer v-model:images="imagesArray" v-model:visible="imageVisible" />
<publish-moment v-model:show="dynamicVisible" :actId="selectActId" @published="getListData"></publish-moment>
</template>
<script setup>
import {ref, reactive, onMounted, computed, h} from 'vue';
import {Toast} from 'tdesign-mobile-vue';
import {useRequest} from "@/utils/request";
import { AddIcon } from 'tdesign-icons-vue-next';
import PublishMoment from "@/pages/activity/dynamic/PublishMoment.vue";
import moment from "moment";
const iconFunc = () => h(AddIcon, { size: '24px' });
const request = useRequest()
const actList = ref([])
const imagesArray = ref([])
const imageVisible = ref(false)
const refresherTriggered = ref(false);
const loading = ref(false);
const hasMore = ref(true);
const dataList = ref([]);
const content = ref(null);
const dynamicVisible = ref(false);
const actOptions = computed(() => {
return actList.value.map(item => {
return {
value: item.id,
label: item.title
}
})
})
const selectActId = ref(null)
const pageForm = reactive({
activityId: null,
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: '',
status: '' // 全部
})
async function onClick() {
dynamicVisible.value = true
}
async function onPraise(row) {
request.post('/client/activity/dynamic/praise/' + row.id).then(res=>{
if(res.code===0){
getListData(false)
}else{
Toast({message: res.msg, theme: 'error'});
}
})
}
async function listMineAct() {
try {
const {data, code, msg} = await request.get('/client/activity/list-mine-act')
if (code === 0) {
actList.value = data
if (actList.value.length) {
selectActId.value = actList.value[0].id
}
} else {
Toast.error(msg)
}
} catch (e) {
Toast.error(e.message)
}
}
async function onView(src) {
console.log(src)
imagesArray.value = src
imageVisible.value = true
}
// 触底加载更多
const handleScrollToBottom = () => {
if (loading.value || !hasMore.value) return;
getListData();
};
//下拉刷新
const handleRefresh = () => {
if (loading.value) {
refresherTriggered.value = false;
return;
}
refresherTriggered.value = true;
pageForm.pageNumber = 1;
getListData(true);
};
// 获取列表数据
const getListData = async (isRefresh = false) => {
if (loading.value) return;
loading.value = true;
if (isRefresh) {
pageForm.pageNumber = 1;
}
// 延时1秒,模拟网络请求
await new Promise(resolve => setTimeout(resolve, 1000));
try {
const response = await useRequest().post('/client/activity/dynamic/list', {
pageForm: JSON.stringify(pageForm),
activityId: selectActId.value
});
if (response.code === 0) {
const {list, totalCount} = response.data;
if (isRefresh) {
dataList.value = list;
} else {
dataList.value = [...dataList.value, ...list];
}
pageForm.totalCount = totalCount;
hasMore.value = dataList.value.length < totalCount;
pageForm.pageNumber++;
} else {
Toast({message: '获取列表失败', theme: 'error'});
}
} catch (error) {
Toast({message: '获取列表失败', theme: 'error'});
} finally {
loading.value = false;
// 重置下拉刷新状态
if (refresherTriggered.value) {
refresherTriggered.value = false;
}
}
};
onMounted(() => {
listMineAct();
getListData();
});
</script>
<style scoped lang="less">
.header {
position: relative;
height: 245px;
overflow: hidden;
}
.header-bg {
width: 100%;
height: 100%;
object-fit: cover;
}
.textarea {
height: 300px;
width: 100%;
}
.list-scroll-view {
flex: 1;
height: 0;
}
.page-container {
background: white;
}
.content-container {
padding: 16px;
}
.content-container-header {
display: flex;
align-items: center;
.title {
font-weight: bold;
color: rgb(35, 110, 180);
margin-bottom: 2px;
}
.content {
font-size: 13px;
}
}
.content-container-text {
margin-top: 6px;
}
.content-container-footer {
display: flex;
justify-content: space-between;
margin-bottom: 4px;
.t-icon {
font-size: 18px;
}
.time {
color: grey;
}
}
.button-group {
background-color: var(--bg-color-demo, #fff);
box-sizing: border-box;
padding: 16px;
display: flex;
justify-content: space-between;
position: relative;
.t-button {
height: 32px;
flex: 1;
&:not(:last-child) {
flex: 1;
margin-right: 16px;
}
}
}
.content-container-pic {
display: flex;
}
</style>
@@ -121,17 +121,7 @@ const isSignUp = ref(null)
const agreementChecked = ref(false)
const formRef = ref(null)
const formData = ref({
unitName: "测试",
contactName: "测试",
contactPhone: "18899998888",
userList: [{
userName: "测试",
sex: "男",
position: "测试",
idCard: "421087200004040010",
phone: "18899998888",
isStay: true
}]
userList: [{}]
})
const unitOptions = ref([
+14 -4
View File
@@ -1,7 +1,9 @@
<template>
<view class="page-container">
<view class="header">
<image class="header-bg" src="https://erp-bucket.pek3b.qingstor.com/assistant/89c4b573-c54f-467a-b703-0bc44679ab08.png" mode="aspectFill"></image>
<image class="header-bg"
src="https://erp-bucket.pek3b.qingstor.com/assistant/89c4b573-c54f-467a-b703-0bc44679ab08.png"
mode="aspectFill"></image>
</view>
<view class="menu-container">
@@ -30,6 +32,12 @@
</view>
<view class="menu-text">项目报名</view>
</view>
<view class="menu-item" @click="navigateTo('/pages/activity/dynamic/index')">
<view class="menu-icon-wrapper blue-bg">
<view class="menu-icon star-icon"></view>
</view>
<view class="menu-text">精彩瞬间</view>
</view>
</view>
<!-- 精选内容区 -->
@@ -41,7 +49,9 @@
<view class="activity-list">
<view class="activity-item" @click="navigateTo('/pages/process/index')">
<image class="activity-image" src="https://erp-bucket.pek3b.qingstor.com/assistant/746c37d6-018d-4c64-8a98-ea9ec8b0b3b5.png" mode="widthFix"></image>
<image class="activity-image"
src="https://erp-bucket.pek3b.qingstor.com/assistant/746c37d6-018d-4c64-8a98-ea9ec8b0b3b5.png"
mode="widthFix"></image>
<view class="activity-info">
<view class="activity-title">一分钟了解运动会流程</view>
<view class="activity-meta">
@@ -56,7 +66,7 @@
</template>
<script setup>
import { onMounted } from "vue";
import {onMounted} from "vue";
function navigateTo(url) {
uni.navigateTo({
@@ -64,7 +74,7 @@ function navigateTo(url) {
})
}
onMounted(()=>{
onMounted(() => {
console.log('...........')
uni.showToast({
title: '欢迎使用',