feat: 添加表显里程矫正功能和故障频次管理
Some checks are pending
continuous-integration/drone/push Build is running

- 在故障添加页面新增表显里程矫正输入框
- 在故障详情页面显示表显里程矫正信息
- 实现故障频次增加功能,允许用户通过按钮增加故障发生频次
- 更新后端服务以支持故障频次的增减和相关数据的返回
This commit is contained in:
zpc 2026-03-28 23:17:34 +08:00
parent 389e434831
commit a5039edcbb
11 changed files with 222 additions and 7 deletions

View File

@ -75,6 +75,16 @@
/>
</view>
<view class="form-group">
<text class="form-label">表显里程矫正</text>
<input
class="form-input"
v-model="form.mileageCorrection"
placeholder="选填"
placeholder-class="input-placeholder"
/>
</view>
<view class="form-group">
<text class="form-label">所属光缆</text>
<view class="form-display">
@ -145,6 +155,7 @@ const form = reactive({
personnel: '',
faultReason: '',
mileage: '',
mileageCorrection: '',
cableName: '',
latitude: 0,
longitude: 0,
@ -238,7 +249,7 @@ function fallbackPlusLocation(originalErr) {
// #ifdef APP-PLUS
if (typeof plus !== 'undefined' && plus.geolocation) {
console.log('[GPS] 尝试 plus.geolocation 回退定位')
plus.geolocation.getCurrentPosition(
plus.geolocation.getCurrentPosition(
(pos) => {
console.log('[GPS] plus定位成功:', JSON.stringify({
latitude: pos.coords.latitude,
@ -308,6 +319,7 @@ async function handleSubmit() {
//
const watermarkLines = [
`${form.faultTime} ${form.personnel}`,
`故障原因:${form.faultReason || ''}`,
`经度:${form.longitude} 纬度:${form.latitude}`
]
const watermarkedPhotos = []
@ -343,6 +355,7 @@ async function handleSubmit() {
personnel: form.personnel,
faultReason: form.faultReason,
mileage: form.mileage,
mileageCorrection: form.mileageCorrection,
latitude: String(form.latitude),
longitude: String(form.longitude),
remark: form.remark

View File

@ -48,7 +48,18 @@
<view class="info-area">
<view class="info-row">
<text class="info-label">故障时间</text>
<text class="info-value">{{ detail.faultTime }}</text>
<view class="info-value fault-time-list">
<text class="fault-time-item" v-for="(t, i) in allFaultTimes" :key="i">{{ t }}</text>
</view>
</view>
<view class="info-row">
<text class="info-label">故障发生频次</text>
<view class="info-value freq-row">
<text class="freq-value">{{ detail.faultCount }}</text>
<view class="freq-btn" @click="handleIncrement">
<text class="freq-btn-text">增加频次</text>
</view>
</view>
</view>
<view class="info-row">
<text class="info-label">人员</text>
@ -60,7 +71,11 @@
</view>
<view class="info-row">
<text class="info-label">表显故障里程</text>
<text class="info-value">{{ detail.mileage }}</text>
<text class="info-value">{{ displayMileage }}</text>
</view>
<view class="info-row" v-if="detail.mileageCorrection">
<text class="info-label">表显里程矫正</text>
<text class="info-value">{{ detail.mileageCorrection }}</text>
</view>
<view class="info-row">
<text class="info-label">所属光缆</text>
@ -89,7 +104,7 @@
<script setup>
import { ref, reactive, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { getFaultDetail } from '@/services/trunk'
import { getFaultDetail, incrementFaultCount } from '@/services/trunk'
import { BASE_URL } from '@/services/api'
import { openNavigation } from '@/utils/navigation'
@ -107,7 +122,34 @@ const detail = reactive({
location: '',
latitude: 0,
longitude: 0,
remark: ''
remark: '',
mileageCorrection: '',
faultCount: 1,
faultTimes: []
})
const incrementing = ref(false)
const allFaultTimes = computed(() => {
const times = []
if (detail.faultTime) {
times.push(detail.faultTime)
}
if (detail.faultTimes && detail.faultTimes.length > 0) {
detail.faultTimes.forEach(t => {
times.push(t.faultTime || t.FaultTime || '')
})
}
times.sort()
return times
})
const displayMileage = computed(() => {
const m = parseFloat(detail.mileage)
const c = parseFloat(detail.mileageCorrection)
if (!isNaN(m) && !isNaN(c)) {
return String(Math.round((m + c) * 10000) / 10000)
}
return detail.mileage || ''
})
const hasLocation = computed(() => {
@ -124,6 +166,7 @@ async function loadDetail() {
detail.personnel = d.personnel || ''
detail.faultReason = d.faultReason || ''
detail.mileage = d.mileage || ''
detail.mileageCorrection = d.mileageCorrection || ''
detail.cableName = d.cableName || ''
detail.location = d.location || ''
detail.latitude = d.latitude || 0
@ -133,6 +176,8 @@ async function loadDetail() {
detail.location = `经度:${detail.longitude} 纬度:${detail.latitude}`
}
detail.remark = d.remark || ''
detail.faultCount = d.faultCount || 1
detail.faultTimes = d.faultTimes || []
imageList.value = (d.images || []).map((img, i) => {
const url = img.url || img.imageUrl || ''
imageStatus[i] = 'loading'
@ -164,6 +209,25 @@ function previewImage(index) {
})
}
async function handleIncrement() {
if (incrementing.value) return
incrementing.value = true
try {
const res = await incrementFaultCount(faultId.value)
if (res.code === 200 && res.data) {
detail.faultCount = res.data.faultCount
detail.faultTimes = res.data.faultTimes || []
uni.showToast({ title: '频次已增加', icon: 'success' })
} else {
uni.showToast({ title: res.msg || '操作失败', icon: 'none' })
}
} catch (err) {
uni.showToast({ title: '网络异常', icon: 'none' })
} finally {
incrementing.value = false
}
}
function handleNavigate() {
openNavigation(detail.latitude, detail.longitude, detail.location || '故障地点')
}
@ -308,6 +372,41 @@ onLoad((options) => {
word-break: break-all;
}
.fault-time-list {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.fault-time-item {
font-size: 26rpx;
color: #333;
line-height: 1.6;
}
.freq-row {
display: flex;
align-items: center;
gap: 20rpx;
}
.freq-value {
font-size: 30rpx;
font-weight: 600;
color: #1A73EC;
}
.freq-btn {
background: #1A73EC;
border-radius: 8rpx;
padding: 8rpx 24rpx;
}
.freq-btn-text {
color: #fff;
font-size: 24rpx;
}
.bottom-bar {
position: fixed;
bottom: 0;

View File

@ -1,4 +1,4 @@
import { get, BASE_URL } from './api'
import { get, post, BASE_URL } from './api'
import store from '@/store'
export const getCableList = (deptId) =>
@ -42,5 +42,8 @@ export function addFault(formData) {
})
}
export const incrementFaultCount = (id) =>
post(`/business/OdfCableFaults/incrementFaultCount/${id}`)
export const searchCablesAndFaults = (deptId, keyword) =>
get('/business/OdfCables/search', { deptId, keyword })

View File

@ -62,6 +62,18 @@ namespace ZR.Admin.WebApi.Controllers.Business
return ToResponse(response);
}
/// <summary>
/// 增加故障频次
/// </summary>
[HttpPost("incrementFaultCount/{id}")]
[ActionPermissionFilter(Permission = "odfcablefaults:list")]
[Log(Title = "干线故障", BusinessType = BusinessType.UPDATE)]
public IActionResult IncrementFaultCount(int id)
{
var response = _OdfCableFaultsService.IncrementFaultCount(id);
return SUCCESS(response);
}
/// <summary>
/// 删除故障并级联删除图片
/// </summary>

View File

@ -38,6 +38,8 @@ namespace ZR.Model.Business.Dto
public string Mileage { get; set; }
public string MileageCorrection { get; set; }
public string Location { get; set; }
public decimal Latitude { get; set; }

View File

@ -0,0 +1,18 @@
namespace ZR.Model.Business
{
/// <summary>
/// 故障频次时间记录
/// </summary>
[SugarTable("odf_cable_fault_times")]
public class OdfCableFaultTimes
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public int FaultId { get; set; }
public DateTime FaultTime { get; set; }
public DateTime? CreatedAt { get; set; }
}
}

View File

@ -37,6 +37,11 @@ namespace ZR.Model.Business
/// </summary>
public string? Mileage { get; set; }
/// <summary>
/// 表显里程矫正
/// </summary>
public string? MileageCorrection { get; set; }
/// <summary>
/// 地点描述
/// </summary>
@ -71,5 +76,10 @@ namespace ZR.Model.Business
/// 更新时间
/// </summary>
public DateTime? UpdatedAt { get; set; }
/// <summary>
/// 故障发生频次
/// </summary>
public int FaultCount { get; set; } = 1;
}
}

View File

@ -38,5 +38,10 @@ namespace ZR.Service.Business.IBusinessService
/// 批量导入故障
/// </summary>
(int successCount, int errorCount, string errorMsg) ImportFaults(List<OdfCableFaultImportDto> list);
/// <summary>
/// 增加故障频次
/// </summary>
object IncrementFaultCount(int id);
}
}

View File

@ -36,6 +36,7 @@ namespace ZR.Service.Business
f.Personnel,
f.FaultReason,
f.Mileage,
f.MileageCorrection,
f.Location,
f.Latitude,
f.Longitude,
@ -72,6 +73,7 @@ namespace ZR.Service.Business
f.Personnel,
f.FaultReason,
f.Mileage,
f.MileageCorrection,
f.Location,
f.Latitude,
f.Longitude,
@ -94,6 +96,12 @@ namespace ZR.Service.Business
.Select(img => new { img.Id, img.ImageUrl })
.ToList();
var faultTimes = Context.Queryable<OdfCableFaultTimes>()
.Where(t => t.FaultId == id)
.OrderBy(t => t.FaultTime)
.Select(t => new { t.Id, t.FaultTime })
.ToList();
return new
{
fault.Id,
@ -102,12 +110,15 @@ namespace ZR.Service.Business
fault.Personnel,
fault.FaultReason,
fault.Mileage,
fault.MileageCorrection,
fault.Location,
fault.Latitude,
fault.Longitude,
fault.Remark,
fault.CableName,
fault.CreatedAt,
FaultCount = Context.Queryable<OdfCableFaults>().Where(f => f.Id == id).First()?.FaultCount ?? 1,
FaultTimes = faultTimes,
Images = images
};
}
@ -140,6 +151,7 @@ namespace ZR.Service.Business
Personnel = dto.Personnel,
FaultReason = dto.FaultReason,
Mileage = dto.Mileage,
MileageCorrection = dto.MileageCorrection,
Location = dto.Location,
Latitude = dto.Latitude,
Longitude = dto.Longitude,
@ -220,6 +232,43 @@ namespace ZR.Service.Business
return GetList(parm);
}
/// <summary>
/// 增加故障频次FaultCount+1同时插入一条时间记录
/// </summary>
public object IncrementFaultCount(int id)
{
var fault = GetFirst(f => f.Id == id);
if (fault == null)
{
throw new CustomException("故障记录不存在");
}
fault.FaultCount += 1;
fault.UpdatedAt = DateTime.Now;
Update(fault, true);
var now = DateTime.Now;
var timeRecord = new OdfCableFaultTimes
{
FaultId = id,
FaultTime = now,
CreatedAt = now
};
Context.Insertable(timeRecord).ExecuteCommand();
var faultTimes = Context.Queryable<OdfCableFaultTimes>()
.Where(t => t.FaultId == id)
.OrderBy(t => t.FaultTime)
.Select(t => new { t.Id, t.FaultTime })
.ToList();
return new
{
FaultCount = fault.FaultCount,
FaultTimes = faultTimes
};
}
/// <summary>
/// 查询表达式
/// </summary>

View File

@ -84,7 +84,11 @@
<el-table-column prop="faultReason" label="故障原因" align="center" :show-overflow-tooltip="true" v-if="columns.showColumn('faultReason')" />
<el-table-column prop="mileage" label="表显故障里程" align="center" :show-overflow-tooltip="true" v-if="columns.showColumn('mileage')" />
<el-table-column prop="cableName" label="所属光缆" align="center" :show-overflow-tooltip="true" v-if="columns.showColumn('cableName')" />
<el-table-column prop="location" label="地点" align="center" :show-overflow-tooltip="true" v-if="columns.showColumn('location')" />
<el-table-column label="地点" align="center" :show-overflow-tooltip="true" v-if="columns.showColumn('location')">
<template #default="scope">
<span v-if="scope.row.latitude || scope.row.longitude">{{ scope.row.longitude }}, {{ scope.row.latitude }}</span>
</template>
</el-table-column>
<el-table-column prop="createdAt" label="创建时间" align="center" :show-overflow-tooltip="true" v-if="columns.showColumn('createdAt')" />
<el-table-column label="操作" width="120">
<template #default="scope">