From 2c86a8bd60deed0dd0e044bad6fb83f75d19a332 Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期日, 26 十月 2025 15:05:50 +0800
Subject: [PATCH] Merge branch 'feature-task'
---
ruoyi-ui/src/views/task/general/index.vue | 682 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 682 insertions(+), 0 deletions(-)
diff --git a/ruoyi-ui/src/views/task/general/index.vue b/ruoyi-ui/src/views/task/general/index.vue
new file mode 100644
index 0000000..8988020
--- /dev/null
+++ b/ruoyi-ui/src/views/task/general/index.vue
@@ -0,0 +1,682 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="浠诲姟缂栧彿" prop="taskCode">
+ <el-input
+ v-model="queryParams.taskCode"
+ placeholder="璇疯緭鍏ヤ换鍔$紪鍙�"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="浠诲姟绫诲瀷" prop="taskType">
+ <el-select v-model="queryParams.taskType" placeholder="璇烽�夋嫨浠诲姟绫诲瀷" clearable>
+ <el-option
+ v-for="dict in dict.type.sys_task_type"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="浠诲姟鐘舵��" prop="taskStatus">
+ <el-select v-model="queryParams.taskStatus" placeholder="璇烽�夋嫨浠诲姟鐘舵��" clearable>
+ <el-option
+ v-for="dict in dict.type.sys_task_status"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="璁″垝寮�濮嬫椂闂�">
+ <el-date-picker
+ v-model="dateRange"
+ style="width: 240px"
+ value-format="yyyy-MM-dd"
+ type="daterange"
+ range-separator="-"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ ></el-date-picker>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="handleAdd"
+ v-hasPermi="['task:general:add']"
+ >鏂板</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="success"
+ plain
+ icon="el-icon-edit"
+ size="mini"
+ :disabled="single"
+ @click="handleUpdate"
+ v-hasPermi="['task:general:edit']"
+ >淇敼</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['task:general:remove']"
+ >鍒犻櫎</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-download"
+ size="mini"
+ @click="handleExport"
+ v-hasPermi="['task:general:export']"
+ >瀵煎嚭</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="taskList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="浠诲姟缂栧彿" align="center" prop="taskCode">
+ <template slot-scope="scope">
+ <el-button
+ type="text"
+ @click="handleView(scope.row)"
+ v-hasPermi="['task:general:query']"
+ >{{ scope.row.taskCode }}</el-button>
+ </template>
+ </el-table-column>
+ <el-table-column label="浠诲姟绫诲瀷" align="center" prop="taskType" width="120">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_task_type" :value="scope.row.taskType"/>
+ <el-tag v-if="scope.row.taskType === 'EMERGENCY_TRANSFER'" type="danger" size="mini" style="margin-left: 5px;">
+ <i class="el-icon-warning"></i>
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="浠诲姟鐘舵��" align="center" prop="taskStatus">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_task_status" :value="scope.row.taskStatus"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍑哄彂鍦板潃" align="center" prop="departureAddress" show-overflow-tooltip />
+ <el-table-column label="鐩殑鍦板潃" align="center" prop="destinationAddress" show-overflow-tooltip />
+ <el-table-column label="棰勮鍏噷鏁�" align="center" prop="estimatedDistance" width="120">
+ <template slot-scope="scope">
+ <span v-if="scope.row.estimatedDistance">{{ scope.row.estimatedDistance }} km</span>
+ <span v-else style="color: #C0C4CC;">--</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="璁″垝寮�濮嬫椂闂�" align="center" prop="plannedStartTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.plannedStartTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="璁″垝缁撴潫鏃堕棿" align="center" prop="plannedEndTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.plannedEndTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍒涘缓浜�" align="center" prop="creatorName" />
+ <el-table-column label="鎵ц浜�" align="center" prop="assigneeName" />
+ <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-view"
+ @click="handleView(scope.row)"
+ v-hasPermi="['task:general:query']"
+ >鏌ョ湅</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-edit"
+ @click="handleUpdate(scope.row)"
+ v-hasPermi="['task:general:edit']"
+ >淇敼</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-user"
+ @click="handleAssign(scope.row)"
+ v-hasPermi="['task:general:assign']"
+ >鍒嗛厤</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-refresh"
+ @click="handleStatusChange(scope.row)"
+ v-hasPermi="['task:general:status']"
+ >鐘舵��</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['task:general:remove']"
+ >鍒犻櫎</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <!-- 娣诲姞鎴栦慨鏀逛换鍔$鐞嗗璇濇 -->
+ <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+ <el-form-item label="浠诲姟绫诲瀷" prop="taskType">
+ <el-select v-model="form.taskType" placeholder="璇烽�夋嫨浠诲姟绫诲瀷">
+ <el-option
+ v-for="dict in dict.type.sys_task_type"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="浠诲姟鎻忚堪" prop="taskDescription">
+ <el-input v-model="form.taskDescription" type="textarea" placeholder="璇疯緭鍏ヤ换鍔℃弿杩�" />
+ </el-form-item>
+ <el-form-item label="鍑哄彂鍦板潃" prop="departureAddress">
+ <el-input v-model="form.departureAddress" placeholder="璇疯緭鍏ュ嚭鍙戝湴鍧�" />
+ </el-form-item>
+ <el-form-item label="鐩殑鍦板潃" prop="destinationAddress">
+ <el-input v-model="form.destinationAddress" placeholder="璇疯緭鍏ョ洰鐨勫湴鍧�" />
+ </el-form-item>
+
+ <!-- GPS鍧愭爣淇℃伅 -->
+ <el-divider content-position="left">GPS鍧愭爣淇℃伅</el-divider>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鍑哄彂鍦扮粡搴�" prop="departureLongitude">
+ <el-input-number
+ v-model="form.departureLongitude"
+ :precision="7"
+ :step="0.0000001"
+ :min="-180"
+ :max="180"
+ placeholder="璇疯緭鍏ョ粡搴�"
+ style="width: 100%"
+ @change="calculateDistance"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鍑哄彂鍦扮含搴�" prop="departureLatitude">
+ <el-input-number
+ v-model="form.departureLatitude"
+ :precision="7"
+ :step="0.0000001"
+ :min="-90"
+ :max="90"
+ placeholder="璇疯緭鍏ョ含搴�"
+ style="width: 100%"
+ @change="calculateDistance"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鐩殑鍦扮粡搴�" prop="destinationLongitude">
+ <el-input-number
+ v-model="form.destinationLongitude"
+ :precision="7"
+ :step="0.0000001"
+ :min="-180"
+ :max="180"
+ placeholder="璇疯緭鍏ョ粡搴�"
+ style="width: 100%"
+ @change="calculateDistance"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鐩殑鍦扮含搴�" prop="destinationLatitude">
+ <el-input-number
+ v-model="form.destinationLatitude"
+ :precision="7"
+ :step="0.0000001"
+ :min="-90"
+ :max="90"
+ placeholder="璇疯緭鍏ョ含搴�"
+ style="width: 100%"
+ @change="calculateDistance"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-form-item label="棰勮鍏噷鏁�" prop="estimatedDistance">
+ <el-input-number
+ v-model="form.estimatedDistance"
+ :precision="2"
+ :step="0.01"
+ :min="0"
+ placeholder="鑷姩璁$畻"
+ style="width: 200px"
+ :disabled="true"
+ />
+ <span style="margin-left: 10px; color: #909399; font-size: 12px;">
+ <i class="el-icon-info"></i> 鏍规嵁GPS鍧愭爣鑷姩璁$畻
+ </span>
+ </el-form-item>
+ <el-form-item label="璁″垝寮�濮嬫椂闂�" prop="plannedStartTime">
+ <el-date-picker clearable
+ v-model="form.plannedStartTime"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ placeholder="璇烽�夋嫨璁″垝寮�濮嬫椂闂�">
+ </el-date-picker>
+ </el-form-item>
+ <el-form-item label="璁″垝缁撴潫鏃堕棿" prop="plannedEndTime">
+ <el-date-picker clearable
+ v-model="form.plannedEndTime"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ placeholder="璇烽�夋嫨璁″垝缁撴潫鏃堕棿">
+ </el-date-picker>
+ </el-form-item>
+ <el-form-item label="鎵ц浜�" prop="assigneeId">
+ <el-select v-model="form.assigneeId" placeholder="璇烽�夋嫨鎵ц浜�" clearable>
+ <el-option
+ v-for="user in userList"
+ :key="user.userId"
+ :label="user.nickName"
+ :value="user.userId"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="澶囨敞" prop="remark">
+ <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ娉�" />
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+ <el-button @click="cancel">鍙� 娑�</el-button>
+ </div>
+ </el-dialog>
+
+
+ <!-- 浠诲姟鍒嗛厤瀵硅瘽妗� -->
+ <el-dialog title="浠诲姟鍒嗛厤" :visible.sync="assignOpen" width="500px" append-to-body>
+ <el-form ref="assignForm" :model="assignForm" :rules="assignRules" label-width="80px">
+ <el-form-item label="鎵ц浜�" prop="assigneeId">
+ <el-select v-model="assignForm.assigneeId" placeholder="璇烽�夋嫨鎵ц浜�" clearable>
+ <el-option
+ v-for="user in userList"
+ :key="user.userId"
+ :label="user.nickName"
+ :value="user.userId"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="澶囨敞" prop="remark">
+ <el-input v-model="assignForm.remark" type="textarea" placeholder="璇疯緭鍏ュ娉�" />
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitAssign">纭� 瀹�</el-button>
+ <el-button @click="cancelAssign">鍙� 娑�</el-button>
+ </div>
+ </el-dialog>
+
+ <!-- 鐘舵�佸彉鏇村璇濇 -->
+ <el-dialog title="鐘舵�佸彉鏇�" :visible.sync="statusOpen" width="500px" append-to-body>
+ <el-form ref="statusForm" :model="statusForm" :rules="statusRules" label-width="80px">
+ <el-form-item label="浠诲姟鐘舵��" prop="taskStatus">
+ <el-select v-model="statusForm.taskStatus" placeholder="璇烽�夋嫨浠诲姟鐘舵��">
+ <el-option
+ v-for="dict in dict.type.sys_task_status"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="澶囨敞" prop="remark">
+ <el-input v-model="statusForm.remark" type="textarea" placeholder="璇疯緭鍏ュ娉�" />
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitStatusChange">纭� 瀹�</el-button>
+ <el-button @click="cancelStatusChange">鍙� 娑�</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { listTask, getTask, delTask, addTask, updateTask, assignTask, changeTaskStatus } from "@/api/task";
+import { listUser } from "@/api/system/user";
+
+export default {
+ name: "Task",
+ dicts: ['sys_task_type', 'sys_task_status'],
+ data() {
+ return {
+ // 閬僵灞�
+ loading: true,
+ // 閫変腑鏁扮粍
+ ids: [],
+ // 闈炲崟涓鐢�
+ single: true,
+ // 闈炲涓鐢�
+ multiple: true,
+ // 鏄剧ず鎼滅储鏉′欢
+ showSearch: true,
+ // 鎬绘潯鏁�
+ total: 0,
+ // 浠诲姟绠$悊琛ㄦ牸鏁版嵁
+ taskList: [],
+ // 寮瑰嚭灞傛爣棰�
+ title: "",
+ // 鏄惁鏄剧ず寮瑰嚭灞�
+ open: false,
+ // 鏄惁鏄剧ず鍒嗛厤寮瑰嚭灞�
+ assignOpen: false,
+ // 鏄惁鏄剧ず鐘舵�佸彉鏇村脊鍑哄眰
+ statusOpen: false,
+ // 鏃ユ湡鑼冨洿
+ dateRange: [],
+ // 鏌ヨ鍙傛暟
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ taskCode: null,
+ taskType: null,
+ taskStatus: null,
+ plannedStartTimeBegin: null,
+ plannedStartTimeEnd: null,
+ },
+ // 琛ㄥ崟鍙傛暟
+ form: {},
+ // 鍒嗛厤琛ㄥ崟
+ assignForm: {},
+ // 鐘舵�佸彉鏇磋〃鍗�
+ statusForm: {},
+ // 鐢ㄦ埛鍒楄〃
+ userList: [],
+ // 琛ㄥ崟鏍¢獙
+ rules: {
+ taskType: [
+ { required: true, message: "浠诲姟绫诲瀷涓嶈兘涓虹┖", trigger: "change" }
+ ],
+ taskDescription: [
+ { required: true, message: "浠诲姟鎻忚堪涓嶈兘涓虹┖", trigger: "blur" }
+ ],
+ plannedStartTime: [
+ { required: true, message: "璁″垝寮�濮嬫椂闂翠笉鑳戒负绌�", trigger: "blur" }
+ ],
+ plannedEndTime: [
+ { required: true, message: "璁″垝缁撴潫鏃堕棿涓嶈兘涓虹┖", trigger: "blur" }
+ ]
+ },
+ // 鍒嗛厤琛ㄥ崟鏍¢獙
+ assignRules: {
+ assigneeId: [
+ { required: true, message: "鎵ц浜轰笉鑳戒负绌�", trigger: "change" }
+ ]
+ },
+ // 鐘舵�佸彉鏇磋〃鍗曟牎楠�
+ statusRules: {
+ taskStatus: [
+ { required: true, message: "浠诲姟鐘舵�佷笉鑳戒负绌�", trigger: "change" }
+ ]
+ }
+ };
+ },
+ created() {
+ this.getList();
+ this.getUserList();
+ },
+ methods: {
+ /** 鏌ヨ浠诲姟绠$悊鍒楄〃 */
+ getList() {
+ this.loading = true;
+ if (this.dateRange != null && this.dateRange.length === 2) {
+ this.queryParams.plannedStartTimeBegin = this.dateRange[0];
+ this.queryParams.plannedStartTimeEnd = this.dateRange[1];
+ }
+ listTask(this.queryParams).then(response => {
+ this.taskList = response.rows;
+ this.total = response.total;
+ this.loading = false;
+ });
+ },
+ /** 鏌ヨ鐢ㄦ埛鍒楄〃 */
+ getUserList() {
+ listUser().then(response => {
+ this.userList = response.rows;
+ });
+ },
+ // 鍙栨秷鎸夐挳
+ cancel() {
+ this.open = false;
+ this.reset();
+ },
+ // 琛ㄥ崟閲嶇疆
+ reset() {
+ this.form = {
+ taskId: null,
+ taskType: null,
+ taskDescription: null,
+ departureAddress: null,
+ destinationAddress: null,
+ departureLongitude: null,
+ departureLatitude: null,
+ destinationLongitude: null,
+ destinationLatitude: null,
+ estimatedDistance: null,
+ plannedStartTime: null,
+ plannedEndTime: null,
+ assigneeId: null,
+ remark: null
+ };
+ this.resetForm("form");
+ },
+ /** 鎼滅储鎸夐挳鎿嶄綔 */
+ handleQuery() {
+ this.queryParams.pageNum = 1;
+ this.getList();
+ },
+ /** 閲嶇疆鎸夐挳鎿嶄綔 */
+ resetQuery() {
+ this.dateRange = [];
+ this.resetForm("queryForm");
+ this.handleQuery();
+ },
+ // 澶氶�夋閫変腑鏁版嵁
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.taskId)
+ this.single = selection.length!==1
+ this.multiple = !selection.length
+ },
+ /** 鏂板鎸夐挳鎿嶄綔 */
+ handleAdd() {
+ this.reset();
+ this.open = true;
+ this.title = "娣诲姞浠诲姟绠$悊";
+ },
+ /** 淇敼鎸夐挳鎿嶄綔 */
+ handleUpdate(row) {
+ this.reset();
+ const taskId = row.taskId || this.ids
+ getTask(taskId).then(response => {
+ this.form = response.data;
+ this.open = true;
+ this.title = "淇敼浠诲姟绠$悊";
+ });
+ },
+ /** 鏌ョ湅鎸夐挳鎿嶄綔 */
+ handleView(row) {
+ this.$router.push('/task/general-detail/index/' + row.taskId);
+ },
+ /** 鍒嗛厤鎸夐挳鎿嶄綔 */
+ handleAssign(row) {
+ this.assignForm = {
+ taskId: row.taskId,
+ assigneeId: row.assigneeId,
+ remark: null
+ };
+ this.assignOpen = true;
+ },
+ /** 鐘舵�佸彉鏇存寜閽搷浣� */
+ handleStatusChange(row) {
+ this.statusForm = {
+ taskId: row.taskId,
+ taskStatus: row.taskStatus,
+ remark: null
+ };
+ this.statusOpen = true;
+ },
+ /** 鎻愪氦鎸夐挳 */
+ submitForm() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ if (this.form.taskId != null) {
+ updateTask(this.form).then(response => {
+ this.$modal.msgSuccess("淇敼鎴愬姛");
+ this.open = false;
+ this.getList();
+ });
+ } else {
+ addTask(this.form).then(response => {
+ this.$modal.msgSuccess("鏂板鎴愬姛");
+ this.open = false;
+ this.getList();
+ });
+ }
+ }
+ });
+ },
+ /** 鎻愪氦鍒嗛厤 */
+ submitAssign() {
+ this.$refs["assignForm"].validate(valid => {
+ if (valid) {
+ assignTask(this.assignForm.taskId, this.assignForm).then(response => {
+ this.$modal.msgSuccess("鍒嗛厤鎴愬姛");
+ this.assignOpen = false;
+ this.getList();
+ });
+ }
+ });
+ },
+ /** 鎻愪氦鐘舵�佸彉鏇� */
+ submitStatusChange() {
+ this.$refs["statusForm"].validate(valid => {
+ if (valid) {
+ changeTaskStatus(this.statusForm.taskId, this.statusForm).then(response => {
+ this.$modal.msgSuccess("鐘舵�佸彉鏇存垚鍔�");
+ this.statusOpen = false;
+ this.getList();
+ });
+ }
+ });
+ },
+ /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+ handleDelete(row) {
+ const taskIds = row.taskId || this.ids;
+ this.$modal.confirm('鏄惁纭鍒犻櫎浠诲姟绠$悊缂栧彿涓�"' + taskIds + '"鐨勬暟鎹」锛�').then(function() {
+ return delTask(taskIds);
+ }).then(() => {
+ this.getList();
+ this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ }).catch(() => {});
+ },
+ /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+ handleExport() {
+ this.download('task/export', {
+ ...this.queryParams
+ }, `task_${new Date().getTime()}.xlsx`)
+ },
+ /** 鍙栨秷鍒嗛厤 */
+ cancelAssign() {
+ this.assignOpen = false;
+ this.assignForm = {};
+ },
+ /** 鍙栨秷鐘舵�佸彉鏇� */
+ cancelStatusChange() {
+ this.statusOpen = false;
+ this.statusForm = {};
+ },
+
+ /** 璁$畻GPS鍧愭爣璺濈 */
+ calculateDistance() {
+ if (this.form.departureLongitude && this.form.departureLatitude &&
+ this.form.destinationLongitude && this.form.destinationLatitude) {
+
+ // 楠岃瘉鍧愭爣鏈夋晥鎬�
+ if (this.isValidCoordinate(this.form.departureLatitude, this.form.departureLongitude) &&
+ this.isValidCoordinate(this.form.destinationLatitude, this.form.destinationLongitude)) {
+
+ // 浣跨敤Haversine鍏紡璁$畻璺濈
+ const distance = this.calculateHaversineDistance(
+ this.form.departureLatitude, this.form.departureLongitude,
+ this.form.destinationLatitude, this.form.destinationLongitude
+ );
+
+ this.form.estimatedDistance = Math.round(distance * 100) / 100; // 淇濈暀2浣嶅皬鏁�
+ } else {
+ this.form.estimatedDistance = 0;
+ }
+ } else {
+ this.form.estimatedDistance = 0;
+ }
+ },
+
+ /** 楠岃瘉GPS鍧愭爣鏄惁鏈夋晥 */
+ isValidCoordinate(latitude, longitude) {
+ return latitude >= -90 && latitude <= 90 && longitude >= -180 && longitude <= 180;
+ },
+
+ /** 浣跨敤Haversine鍏紡璁$畻涓ょ偣闂磋窛绂� */
+ calculateHaversineDistance(lat1, lon1, lat2, lon2) {
+ const R = 6371; // 鍦扮悆鍗婂緞锛堝叕閲岋級
+ const dLat = this.toRadians(lat2 - lat1);
+ const dLon = this.toRadians(lon2 - lon1);
+ const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
+ Math.cos(this.toRadians(lat1)) * Math.cos(this.toRadians(lat2)) *
+ Math.sin(dLon / 2) * Math.sin(dLon / 2);
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+ return R * c;
+ },
+
+ /** 瑙掑害杞姬搴� */
+ toRadians(degrees) {
+ return degrees * (Math.PI / 180);
+ }
+ }
+};
+</script>
--
Gitblit v1.9.1