同步6/16
This commit is contained in:
@@ -8,16 +8,122 @@
|
||||
</template>
|
||||
<div class="addBuildingFormBody">
|
||||
<div class="formbox">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="150px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-col :span="13">
|
||||
<el-form-item label="活动标题" prop="title">
|
||||
<el-input v-model.trim="form.title" placeholder="请输入活动标题" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-form-item label="活动作者" prop="author">
|
||||
<el-input v-model.trim="form.author" placeholder="请输入活动作者" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="13">
|
||||
<el-form-item label="活动时间" prop="startTime">
|
||||
<el-date-picker
|
||||
v-model="activityTime"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
@update:model-value="
|
||||
(data) => {
|
||||
if (data && data.length > 0) {
|
||||
form.startTime = data[0];
|
||||
form.endTime = data[1];
|
||||
} else {
|
||||
form.startTime = '';
|
||||
form.endTime = '';
|
||||
}
|
||||
}
|
||||
"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始活动"
|
||||
end-placeholder="结束活动"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-form-item label="活动地点" prop="address">
|
||||
<el-input v-model.trim="form.address" placeholder="请输入活动地点" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="11">
|
||||
<el-form-item label="报名截止日期" prop="deadline">
|
||||
<el-date-picker
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
v-model="deadline"
|
||||
@update:model-value="
|
||||
(data) => {
|
||||
if (data) {
|
||||
form.applyDeadline = data;
|
||||
} else {
|
||||
form.applyDeadline = '';
|
||||
}
|
||||
}
|
||||
"
|
||||
type="date"
|
||||
placeholder="请选择报名截止日期"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="作者" prop="author">
|
||||
<el-input v-model.trim="form.author" placeholder="请输入作者" />
|
||||
<el-form-item label="主办方" prop="organizer">
|
||||
<el-input v-model.trim="form.organizer" placeholder="请输入主办方" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系人" prop="contactName">
|
||||
<el-input v-model.trim="form.contactName" placeholder="请输入联系人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系方式" prop="contactName">
|
||||
<el-input v-model.trim="form.contactPhone" placeholder="请输入联系方式" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="活动名额" prop="quota">
|
||||
<div class="flex items-center">
|
||||
<el-input-number v-model.trim.number="form.quota" :min="0" placeholder="0代表无限" />
|
||||
<span class="ml-2 text-gray-500 text-sm" style="font-size: 12px">(填 <b>0</b> 代表<u>不限制名额</u>)</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="活动封面" prop="title">
|
||||
<el-upload
|
||||
ref="upload"
|
||||
class="avatar-uploader"
|
||||
:action="uploadUrl"
|
||||
:show-file-list="false"
|
||||
:on-success="handleAvatarSuccess"
|
||||
:on-exceed="handleExceed"
|
||||
:on-error="handleError"
|
||||
:limit="1"
|
||||
>
|
||||
<img v-if="form.coverImage" :src="form.coverImage" class="avatar" />
|
||||
<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="招募要求">
|
||||
<el-input :row="8" type="textarea" v-model.trim="form.requirements" placeholder="请输入招募要求" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -29,6 +135,69 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- <el-row>
|
||||
<el-col>
|
||||
<el-form-item label="活动签到">
|
||||
<el-switch
|
||||
@change="
|
||||
(val) => {
|
||||
if (val) {
|
||||
initSignMap();
|
||||
}
|
||||
}
|
||||
"
|
||||
v-model="isSignin"
|
||||
active-text="签到"
|
||||
inactive-text="不签到"
|
||||
:active-value="true"
|
||||
:inactive-value="false"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="13">
|
||||
<el-form-item label="签到时间" prop="signinStartTime">
|
||||
<el-date-picker
|
||||
v-model="SigninTime"
|
||||
type="datetimerange"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
range-separator="至"
|
||||
@update:model-value="
|
||||
(data) => {
|
||||
if (data && data.length > 0) {
|
||||
form.signinStartTime = data[0];
|
||||
form.signinEndTime = data[1];
|
||||
} else {
|
||||
form.signinStartTime = '';
|
||||
form.signinEndTime = '';
|
||||
}
|
||||
}
|
||||
"
|
||||
start-placeholder="开始签到"
|
||||
end-placeholder="结束签到"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="isSignin">
|
||||
<el-col>
|
||||
<el-form-item label="签到设置">
|
||||
<div>
|
||||
<div>
|
||||
<el-button type="primary" v-if="isDraw === 0" @click="startDrawCircle">开始设置签到范围</el-button>
|
||||
<el-button type="success" v-if="isDraw === 1" @click="editCircle">编辑签到范围</el-button>
|
||||
<el-button type="warning" v-if="isDraw === 2" @click="stopDrawCircle">结束设置签到范围</el-button>
|
||||
<el-button type="danger" @click="clearCircle">清空签到范围</el-button>
|
||||
</div>
|
||||
<div v-loading="mapReady" class="SignMapbox">
|
||||
<div id="SignMap" style="height: 100%; width: 100%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row> -->
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="handleBack">返回</el-button>
|
||||
@@ -44,44 +213,281 @@
|
||||
import { ref } from 'vue';
|
||||
import PageHeader from '@/components/Pageheader/index.vue';
|
||||
import { addActivity, getActivity, updateActivity } from '@/api/system/Activity';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { com_repair_project_status } = toRefs<any>(proxy?.useDict('com_repair_project_status'));
|
||||
import { genFileId, UploadFiles, UploadInstance, UploadProps, UploadRawFile } from 'element-plus';
|
||||
import AMapLoader from '@amap/amap-jsapi-loader';
|
||||
|
||||
const uploadUrl = import.meta.env.VITE_APP_BASE_API + '/activity/uploadImage';
|
||||
|
||||
const aloaderkey = import.meta.env.VITE_GCJ02_KEY_GD;
|
||||
const VITE_GCJ02_JS_CODE_GD = import.meta.env.VITE_GCJ02_JS_CODE_GD;
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const formRef = ref();
|
||||
const form = ref({
|
||||
'id': null,
|
||||
// 标题
|
||||
'title': '',
|
||||
// 作者
|
||||
'author': '',
|
||||
// 内容
|
||||
'content': '',
|
||||
'status': '0'
|
||||
// 发布状态 0未发布 1己发布
|
||||
'status': '0',
|
||||
// 报名截止日期
|
||||
'applyDeadline': '',
|
||||
// 活动时间
|
||||
'startTime': '',
|
||||
'endTime': '',
|
||||
// 活动地点
|
||||
'address': '',
|
||||
// 主办方
|
||||
'organizer': '',
|
||||
// 联系人
|
||||
'contactName': '',
|
||||
// 联系方式
|
||||
'contactPhone': '',
|
||||
// 开始签到时间
|
||||
'signinStartTime': '',
|
||||
// 结束签到时间
|
||||
'signinEndTime': '',
|
||||
// 活动名额
|
||||
'quota': 0,
|
||||
// 积分奖励
|
||||
'pointsReward': 0,
|
||||
// 活动封面
|
||||
'coverImage': '',
|
||||
// 招募要求
|
||||
'requirements': ''
|
||||
|
||||
// 'SignInfo': {
|
||||
// lng: null, // 经度
|
||||
// lat: null, // 纬度
|
||||
// radius: null // 半径 m
|
||||
// }
|
||||
});
|
||||
const rules = {
|
||||
title: [{ required: true, message: '请输入活动标题', trigger: 'blur' }],
|
||||
author: [{ required: true, message: '请输入作者', trigger: 'blur' }],
|
||||
applyDeadline: [{ required: true, message: '请输入报名截止日期', trigger: 'blur' }],
|
||||
startTime: [{ required: true, message: '请选择开始日期', trigger: 'blur' }],
|
||||
endTime: [{ required: true, message: '请选择结束日期', trigger: 'blur' }],
|
||||
address: [{ required: true, message: '请输入活动地点', trigger: 'blur' }],
|
||||
organizer: [{ required: true, message: '请输入主办方', trigger: 'blur' }],
|
||||
contactName: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
|
||||
contactPhone: [{ required: true, message: '请输入联系方式', trigger: 'blur' }],
|
||||
coverImage: [{ required: true, message: '请上传活动封面', trigger: 'blur' }],
|
||||
content: [{ required: true, message: '请输入内容', trigger: 'blur' }]
|
||||
};
|
||||
const userid = ref();
|
||||
// 报名截止日期
|
||||
const deadline = ref([]);
|
||||
// 有效签到时间
|
||||
const SigninTime = ref([]);
|
||||
// 活动时间
|
||||
const activityTime = ref([]);
|
||||
|
||||
// 上传文件
|
||||
const upload = ref<UploadInstance>();
|
||||
// 上传成功
|
||||
const handleAvatarSuccess: UploadProps['onSuccess'] = (response, uploadFile) => {
|
||||
if (response.data && response.data.url) {
|
||||
form.value.coverImage = response.data.url;
|
||||
}
|
||||
};
|
||||
|
||||
// 超出文件限制
|
||||
const handleExceed: UploadProps['onExceed'] = (files) => {
|
||||
upload.value!.clearFiles();
|
||||
const file = files[0] as UploadRawFile;
|
||||
file.uid = genFileId();
|
||||
upload.value!.handleStart(file);
|
||||
upload.value?.submit();
|
||||
};
|
||||
// 上传失败
|
||||
const handleError: UploadProps['onError'] = (error: Error, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
|
||||
console.log(error);
|
||||
};
|
||||
|
||||
// ! 投诉 ====================================================================================================
|
||||
|
||||
// ! 签到 =======================================
|
||||
const isSignin = ref(false);
|
||||
let AMapLi = null;
|
||||
let map: any = null;
|
||||
let circle: any = null;
|
||||
let circleEditor: any = null;
|
||||
|
||||
let geocoder: any = null;
|
||||
const mapReady = ref(false);
|
||||
let mouseTool = null;
|
||||
|
||||
// 0 开始 1编辑 2结束
|
||||
const isDraw = ref(0);
|
||||
|
||||
onMounted(() => {
|
||||
if (route.query.id) {
|
||||
userid.value = route.query.id;
|
||||
init();
|
||||
}
|
||||
});
|
||||
async function initSignMap() {
|
||||
try {
|
||||
mapReady.value = true;
|
||||
window._AMapSecurityConfig = { securityJsCode: VITE_GCJ02_JS_CODE_GD };
|
||||
console.log('开始执行 AMapLoader.load');
|
||||
const AMap = await AMapLoader.load({
|
||||
key: aloaderkey,
|
||||
version: '2.0',
|
||||
plugins: ['AMap.MouseTool', 'AMap.CircleEditor', 'AMap.Geolocation', 'AMap.Geocoder']
|
||||
});
|
||||
mapReady.value = false;
|
||||
console.log('AMapLoader.load 执行完毕');
|
||||
AMapLi = AMap;
|
||||
map = new AMap.Map('SignMap', {
|
||||
viewMode: '3D',
|
||||
zoom: 11,
|
||||
center: [116.397428, 39.90923]
|
||||
});
|
||||
|
||||
// 解析本地存储的城市信息
|
||||
const villageInfoStr = localStorage.getItem('villageInfo') || '{}';
|
||||
let city = '';
|
||||
try {
|
||||
const villageInfo = JSON.parse(villageInfoStr);
|
||||
city = (villageInfo?.city || '').trim();
|
||||
} catch (err) {
|
||||
console.warn('解析 villageInfo 失败', err);
|
||||
}
|
||||
// 初始化地理编码工具
|
||||
if (city.trim() !== '') {
|
||||
geocoder = new AMap.Geocoder({
|
||||
city: city.trim(),
|
||||
radius: 1000
|
||||
});
|
||||
getGeoCode(city.trim(), map);
|
||||
}
|
||||
|
||||
// 鼠标绘制工具
|
||||
mouseTool = new AMap.MouseTool(map);
|
||||
mouseTool.on('draw', (e: any) => {
|
||||
// 移除旧围栏
|
||||
if (circle) {
|
||||
map.remove(circle);
|
||||
}
|
||||
circle = e.obj;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('高德地图初始化失败:', error);
|
||||
}
|
||||
}
|
||||
// 获取 城市经纬度并定位中心
|
||||
const getGeoCode = (address, map) => {
|
||||
geocoder.getLocation(address, (status: string, result: any) => {
|
||||
if (status === 'complete' && result.geocodes.length > 0) {
|
||||
const geo = result.geocodes[0];
|
||||
const lng = geo.location.lng;
|
||||
const lat = geo.location.lat;
|
||||
map.setCenter([lng, lat]);
|
||||
map.setZoom(15);
|
||||
} else {
|
||||
console.log('未找到该地址');
|
||||
}
|
||||
});
|
||||
};
|
||||
// 开始绘制圆形
|
||||
const startDrawCircle = () => {
|
||||
resetCircle();
|
||||
if (!mouseTool) return;
|
||||
isDraw.value = 1; // 编辑
|
||||
mouseTool.circle({
|
||||
strokeColor: '#1890ff',
|
||||
strokeWeight: 3,
|
||||
fillColor: 'rgba(24, 144, 255, 0.2)',
|
||||
fillOpacity: 0.4
|
||||
});
|
||||
};
|
||||
// 停止绘制圆形
|
||||
const stopDrawCircle = () => {
|
||||
if (!mouseTool) return;
|
||||
if (mouseTool) {
|
||||
mouseTool.close(false);
|
||||
}
|
||||
if (circleEditor) {
|
||||
circleEditor.close();
|
||||
circleEditor = null;
|
||||
}
|
||||
isDraw.value = 0; // 开始
|
||||
mouseTool.close(false);
|
||||
if (circle) {
|
||||
const center = circle.getCenter();
|
||||
const radius = circle.getRadius();
|
||||
console.log('中心点:', [center.lng, center.lat]);
|
||||
console.log('半径:', radius, typeof radius);
|
||||
// form.value.SignInfo.lat = center.lat;
|
||||
// form.value.SignInfo.lng = center.lng;
|
||||
// form.value.SignInfo.radius = center.radius;
|
||||
}
|
||||
};
|
||||
|
||||
// 编辑 圆形
|
||||
const editCircle = () => {
|
||||
if (!circle) return;
|
||||
if (mouseTool) {
|
||||
mouseTool.close(false);
|
||||
}
|
||||
isDraw.value = 2; // 结束
|
||||
circleEditor = new AMapLi.CircleEditor(map, circle);
|
||||
circleEditor.open();
|
||||
};
|
||||
|
||||
// 删除圆形
|
||||
const clearCircle = () => {
|
||||
// resetCircle();
|
||||
isDraw.value = 0; // 开始
|
||||
ElMessage.success('全部清除');
|
||||
};
|
||||
// 重置
|
||||
const resetCircle = () => {
|
||||
// 不能绘画
|
||||
if (mouseTool) {
|
||||
mouseTool.close(false);
|
||||
}
|
||||
// 清除圆形
|
||||
if (circle) {
|
||||
map.remove(circle);
|
||||
circle = null;
|
||||
}
|
||||
// 不能编辑
|
||||
if (circleEditor) {
|
||||
circleEditor.close();
|
||||
circleEditor = null;
|
||||
}
|
||||
};
|
||||
|
||||
function init() {
|
||||
getActivity(userid.value).then((res) => {
|
||||
form.value = {
|
||||
...form.value,
|
||||
...res.data
|
||||
};
|
||||
console.log(form.value);
|
||||
activityTime.value = [res.data.startTime, res.data.endTime];
|
||||
SigninTime.value = [res.data.signinStartTime, res.data.signinEndTime];
|
||||
deadline.value = [res.data.applyDeadline];
|
||||
|
||||
// if (res.data?.SignInfo !== null) {
|
||||
// isSignin.value = true;
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
if (route.query.id) {
|
||||
userid.value = route.query.id;
|
||||
init();
|
||||
}
|
||||
|
||||
// ! 提交========================================
|
||||
// 提交
|
||||
const submitForm = () => {
|
||||
console.log(form.value);
|
||||
// if (!isSignin.value) {
|
||||
// form.value.SignInfo = null;
|
||||
// }
|
||||
formRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
if (userid.value) {
|
||||
@@ -105,12 +511,63 @@ function handleBack() {
|
||||
path: '/repair/Activity'
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 销毁地图及所有工具实例(防内存泄漏、重复初始化)
|
||||
*/
|
||||
function destroyMapInstance() {
|
||||
if (map) {
|
||||
map.destroy();
|
||||
map = null;
|
||||
}
|
||||
mouseTool = null;
|
||||
geocoder = null;
|
||||
circle = null;
|
||||
AMapLi = null;
|
||||
mapReady.value = false;
|
||||
}
|
||||
onUnmounted(() => {
|
||||
// destroyMapInstance();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.SignMapbox {
|
||||
height: 500px;
|
||||
width: 500px;
|
||||
margin-top: 10px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.ResidentMainBox {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.avatar-uploader {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.el-icon.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 158px;
|
||||
height: 158px;
|
||||
text-align: center;
|
||||
}
|
||||
.avatar-uploader .avatar {
|
||||
width: 158px;
|
||||
height: 158px;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed var(--el-border-color);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: var(--el-transition-duration-fast);
|
||||
}
|
||||
|
||||
.ResidentMainBody {
|
||||
margin-top: 20px;
|
||||
flex: 1;
|
||||
|
||||
Reference in New Issue
Block a user