|
|
@@ -118,16 +118,25 @@
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
<el-row :gutter="16">
|
|
|
- <el-col :span="12">
|
|
|
+ <el-col :span="8">
|
|
|
<el-form-item label="紧急联系人" prop="emergencyContact">
|
|
|
<el-input v-model="form.emergencyContact" placeholder="请输入紧急联系人" />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
- <el-col :span="12">
|
|
|
+ <el-col :span="8">
|
|
|
<el-form-item label="紧急电话" prop="emergencyPhone">
|
|
|
<el-input v-model="form.emergencyPhone" placeholder="请输入紧急联系电话" />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
+ <!-- <el-col :span="8">
|
|
|
+ <el-form-item label="请假位置" prop="leaveLocation">
|
|
|
+ <el-input v-model="form.leaveLocation" placeholder="请假位置" disabled>
|
|
|
+ <template #append>
|
|
|
+ <el-button type="primary" @click="openLocationMap" :icon="LocationFilled" title="地图定位"> 定位 </el-button>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col> -->
|
|
|
</el-row>
|
|
|
<el-form-item label="请假原因" prop="leaveReason">
|
|
|
<el-input v-model="form.leaveReason" type="textarea" :rows="2" placeholder="请输入请假原因" />
|
|
|
@@ -224,6 +233,61 @@
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
+
|
|
|
+ <!-- 地图定位弹窗 -->
|
|
|
+ <el-dialog v-model="mapDialogVisible" title="请假位置" width="80%" top="5vh" :before-close="closeMapDialog">
|
|
|
+ <div class="map-container">
|
|
|
+ <div v-if="!form.leaveLocation || form.leaveLocation.trim() === ''" class="no-location-tip">
|
|
|
+ <el-empty description="暂无位置信息">
|
|
|
+ <el-button type="primary" @click="closeMapDialog">关闭</el-button>
|
|
|
+ </el-empty>
|
|
|
+ </div>
|
|
|
+ <div v-else class="location-info">
|
|
|
+ <div class="location-text">
|
|
|
+ <el-tag type="info" size="large">
|
|
|
+ <el-icon><LocationFilled /></el-icon>
|
|
|
+ {{ form.leaveLocation }}
|
|
|
+ </el-tag>
|
|
|
+ </div>
|
|
|
+ <div class="map-placeholder">
|
|
|
+ <div class="map-tips">
|
|
|
+ <el-alert
|
|
|
+ title="地图功能提示"
|
|
|
+ type="info"
|
|
|
+ :closable="false"
|
|
|
+ description="地图组件可集成百度地图、高德地图等第三方地图服务来显示具体位置。当前显示位置信息文本。"
|
|
|
+ >
|
|
|
+ </el-alert>
|
|
|
+ <div class="coordinates-display" v-if="parsedLocation">
|
|
|
+ <p><strong>位置解析:</strong></p>
|
|
|
+ <p v-if="parsedLocation.type === 'coordinates'">
|
|
|
+ <span>纬度:{{ parsedLocation.latitude }}</span
|
|
|
+ ><br />
|
|
|
+ <span>经度:{{ parsedLocation.longitude }}</span>
|
|
|
+ </p>
|
|
|
+ <p v-else>
|
|
|
+ <span>位置描述:{{ parsedLocation.address }}</span>
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <!-- 这里可以集成真实的地图组件 -->
|
|
|
+ <div class="mock-map">
|
|
|
+ <div class="map-icon">🗺️</div>
|
|
|
+ <p>地图显示区域</p>
|
|
|
+ <small>(可集成百度地图、高德地图等)</small>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button @click="closeMapDialog">关闭</el-button>
|
|
|
+ <el-button type="primary" @click="openExternalMap" v-if="parsedLocation && parsedLocation.type === 'coordinates'">
|
|
|
+ 在外部地图中查看
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
@@ -233,7 +297,7 @@ import { ref, computed, onMounted, reactive, toRefs, nextTick, getCurrentInstanc
|
|
|
import ElMessage from 'element-plus/es/components/message/index';
|
|
|
import ElMessageBox from 'element-plus/es/components/message-box/index';
|
|
|
import ElLoading from 'element-plus/es/components/loading/index';
|
|
|
-import { UploadFilled, Document, Loading, Download, Delete } from '@element-plus/icons-vue';
|
|
|
+import { UploadFilled, Document, Loading, Download, Delete, LocationFilled } from '@element-plus/icons-vue';
|
|
|
import { getToken } from '@/utils/auth';
|
|
|
import ImagePreview from '@/components/ImagePreview/index.vue';
|
|
|
import request from '@/utils/request';
|
|
|
@@ -362,6 +426,48 @@ const dialogVisible = reactive<DialogOption>({
|
|
|
title: '流程定义'
|
|
|
});
|
|
|
|
|
|
+// 地图弹窗状态
|
|
|
+const mapDialogVisible = ref(false);
|
|
|
+
|
|
|
+// 解析后的位置信息
|
|
|
+const parsedLocation = computed(() => {
|
|
|
+ if (!form.leaveLocation || form.leaveLocation.trim() === '') {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ const location = form.leaveLocation.trim();
|
|
|
+
|
|
|
+ // 尝试解析经纬度格式: "纬度: xxx, 经度: xxx"
|
|
|
+ const coordsRegex = /纬度:\s*([\d.-]+),\s*经度:\s*([\d.-]+)/;
|
|
|
+ const coordsMatch = location.match(coordsRegex);
|
|
|
+
|
|
|
+ if (coordsMatch) {
|
|
|
+ return {
|
|
|
+ type: 'coordinates',
|
|
|
+ latitude: parseFloat(coordsMatch[1]),
|
|
|
+ longitude: parseFloat(coordsMatch[2])
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // 尝试解析简单经纬度格式: "lat,lng" 或 "lat, lng"
|
|
|
+ const simpleRegex = /^([\d.-]+),\s*([\d.-]+)$/;
|
|
|
+ const simpleMatch = location.match(simpleRegex);
|
|
|
+
|
|
|
+ if (simpleMatch) {
|
|
|
+ return {
|
|
|
+ type: 'coordinates',
|
|
|
+ latitude: parseFloat(simpleMatch[1]),
|
|
|
+ longitude: parseFloat(simpleMatch[2])
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // 其他情况当作地址处理
|
|
|
+ return {
|
|
|
+ type: 'address',
|
|
|
+ address: location
|
|
|
+ };
|
|
|
+});
|
|
|
+
|
|
|
//提交组件
|
|
|
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
|
|
//审批记录组件
|
|
|
@@ -988,6 +1094,51 @@ const cancel = () => {
|
|
|
emit('cancel');
|
|
|
};
|
|
|
|
|
|
+// 打开地图定位弹窗
|
|
|
+const openLocationMap = () => {
|
|
|
+ if (!form.leaveLocation || form.leaveLocation.trim() === '') {
|
|
|
+ ElMessage.warning('暂无位置信息可显示');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ mapDialogVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+// 关闭地图弹窗
|
|
|
+const closeMapDialog = () => {
|
|
|
+ mapDialogVisible.value = false;
|
|
|
+};
|
|
|
+
|
|
|
+// 在外部地图中查看
|
|
|
+const openExternalMap = () => {
|
|
|
+ if (!parsedLocation.value || parsedLocation.value.type !== 'coordinates') {
|
|
|
+ ElMessage.warning('无法获取有效的坐标信息');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const { latitude, longitude } = parsedLocation.value;
|
|
|
+
|
|
|
+ // 提供多种地图选择
|
|
|
+ ElMessageBox.confirm('选择要使用的地图服务:', '打开外部地图', {
|
|
|
+ confirmButtonText: '百度地图',
|
|
|
+ cancelButtonText: '高德地图',
|
|
|
+ type: 'info',
|
|
|
+ distinguishCancelAndClose: true
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ // 百度地图
|
|
|
+ const baiduUrl = `https://api.map.baidu.com/marker?location=${latitude},${longitude}&title=请假位置&content=${encodeURIComponent(form.leaveLocation)}&output=html&src=webapp`;
|
|
|
+ window.open(baiduUrl, '_blank');
|
|
|
+ })
|
|
|
+ .catch((action) => {
|
|
|
+ if (action === 'cancel') {
|
|
|
+ // 高德地图
|
|
|
+ const gaodeUrl = `https://uri.amap.com/marker?position=${longitude},${latitude}&name=请假位置&src=webapp`;
|
|
|
+ window.open(gaodeUrl, '_blank');
|
|
|
+ }
|
|
|
+ // 如果是 close,则不执行任何操作
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
// 监听 isLeaveSchool 字段变化,更新销假状态
|
|
|
// watch(
|
|
|
// () => form.isLeaveSchool,
|
|
|
@@ -1640,4 +1791,93 @@ onMounted(() => {
|
|
|
:deep(.el-card .el-card__header) {
|
|
|
border-bottom: 0px !important;
|
|
|
}
|
|
|
+
|
|
|
+/* 地图弹窗样式 */
|
|
|
+.map-container {
|
|
|
+ min-height: 500px;
|
|
|
+ max-height: 70vh;
|
|
|
+ overflow-y: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.no-location-tip {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ min-height: 300px;
|
|
|
+}
|
|
|
+
|
|
|
+.location-info {
|
|
|
+ padding: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.location-text {
|
|
|
+ margin-bottom: 16px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.location-text .el-tag {
|
|
|
+ padding: 8px 16px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.location-text .el-icon {
|
|
|
+ margin-right: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.map-placeholder {
|
|
|
+ margin-top: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.map-tips {
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.coordinates-display {
|
|
|
+ margin: 16px 0;
|
|
|
+ padding: 12px;
|
|
|
+ background: #f8f9fa;
|
|
|
+ border-radius: 6px;
|
|
|
+ border-left: 4px solid #409eff;
|
|
|
+}
|
|
|
+
|
|
|
+.coordinates-display p {
|
|
|
+ margin: 8px 0;
|
|
|
+ line-height: 1.5;
|
|
|
+}
|
|
|
+
|
|
|
+.coordinates-display strong {
|
|
|
+ color: #303133;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.mock-map {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ min-height: 200px;
|
|
|
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
|
|
+ border: 2px dashed #d0d7de;
|
|
|
+ border-radius: 8px;
|
|
|
+ color: #666;
|
|
|
+ text-align: center;
|
|
|
+ margin-top: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.map-icon {
|
|
|
+ font-size: 48px;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.mock-map p {
|
|
|
+ margin: 4px 0;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.mock-map small {
|
|
|
+ color: #999;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
</style>
|