。。。

main
hs 2025-09-02 16:22:17 +08:00
parent 1a4cebae9c
commit 6351d00c4b
58 changed files with 680 additions and 991 deletions

View File

@ -234,6 +234,15 @@
// 把 BD09 -> WGS84 转换后的点回传给宿主
fnConvertorBd09ToWgs84Data2(e.latlng.lng, e.latlng.lat);
notifyHost({type:'point_selected', ok:true, lng:e.latlng.lng, lat:e.latlng.lat});
// // 直接把BD09回传
// notifyHost({type:'converted', longitue: e.latlng.lng, latitude: e.latlng.lat});
// notifyHost({
// type: 'point_selected',
// ok: true,
// lng: e.latlng.lng,
// lat: e.latlng.lat
// });
}
} catch (err) {
console.error('MapClick error', err);

View File

@ -1,380 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>特殊作业扎点</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<style>
body, html, #container {
overflow: hidden;
width: 100%;
height: 100%;
margin: 0;
font-family: "微软雅黑";
}
#hint {
position: absolute;
z-index: 9999;
left: 10px;
top: 10px;
padding: 6px 10px;
background: rgba(255,255,255,0.9);
border-radius: 4px;
font-size: 12px;
}
</style>
<!-- Baidu Map WebGL (保留你的 key) -->
<script type="text/javascript"
src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=OElqFYoKiAH8KFtph8ftLKF5NlNrbCUr"></script>
<script src="./uni.webview.1.5.4.js"></script>
</head>
<body onload="onLoad()">
<div id="container"></div>
<div id="hint" style="display:none"></div>
</body>
<script>
// 地图与数据容器
var map = null;
var marker = null;
var GSON_LON_LAT_WSG84 = []; // WGS84 多点 [[lon,lat,alt], ...]
var GSON_LON_LAT_BD09 = []; // 转换后的 BD09 二维点 [[lng,lat],...]
var convertor = null;
// ---------------------------
// 通用通知宿主Flutter / 原生 / web
// 会尝试多种桥接方式
// data 可以是对象或字符串
// ---------------------------
function notifyHost(data) {
try {
// prefer passing object where supported
if (window.JS && typeof window.JS.postMessage === 'function') {
// webview_flutter JavaScriptChannel expects string
var payload = (typeof data === 'string') ? data : JSON.stringify(data);
window.JS.postMessage(payload);
return;
}
if (window.flutter_inappwebview && typeof window.flutter_inappwebview.callHandler === 'function') {
// flutter_inappwebview can accept objects
window.flutter_inappwebview.callHandler('messageHandler', data);
return;
}
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.JS && typeof window.webkit.messageHandlers.JS.postMessage === 'function') {
window.webkit.messageHandlers.JS.postMessage(data);
return;
}
// fallback to uni (if present) to keep backward compatibility
if (window.uni && typeof window.uni.postMessage === 'function') {
window.uni.postMessage({data: data});
return;
}
// last resort, console (useful for debugging)
console.log('notifyHost:', data);
} catch (e) {
console.error('notifyHost error:', e);
}
}
// ---------------------------
// 尝试从 URL 初始化(如果 Flutter 把参数拼在 URL 上)
// 支持参数: longitude, latitude, GSON (JSON string, 已 encodeURIComponent)
// ---------------------------
function tryInitFromUrl() {
try {
const params = new URLSearchParams(window.location.search);
const lon = params.get('longitude');
const lat = params.get('latitude');
const gsonRaw = params.get('GSON'); // 预期是 encodeURIComponent(JSON.stringify([...]))
var has = false;
if (lon && lat) has = true;
if (gsonRaw) has = true;
if (!has) return false;
var gson = null;
if (gsonRaw) {
try {
gson = JSON.parse(decodeURIComponent(gsonRaw));
} catch (e) {
// 如果直接是未 encode 的 JSON 字符串,也尝试解析
try { gson = JSON.parse(gsonRaw); } catch (e2) { gson = null; }
}
}
// 使用从 url 获取到的数据执行初始化
initWithData({
longitude: parseFloat(lon),
latitude: parseFloat(lat),
GSON: gson
});
return true;
} catch (e) {
console.warn('tryInitFromUrl error', e);
return false;
}
}
// ---------------------------
// Flutter/宿主可调用的初始化函数
// 支持两种调用方式:
// 1) initWithData({longitude: xx, latitude: yy, GSON: [...]})
// 2) initWithData(longitude, latitude, GSONArray)
// GSONArray 结构应与原来一致([[lon,lat,alt], ...]
// ---------------------------
window.initWithData = function() {
var args = arguments;
var payload = {};
if (args.length === 1 && typeof args[0] === 'object') {
payload = args[0];
} else {
// try positional
payload.longitude = args[0];
payload.latitude = args[1];
payload.GSON = args[2];
}
try {
if (!payload) payload = {};
// default safe parse
var lon = Number(payload.longitude) || 0;
var lat = Number(payload.latitude) || 0;
var gson = payload.GSON || [];
// ensure convertor exists
if (!convertor && window.BMapGL && typeof BMapGL.Convertor === 'function') {
convertor = new BMapGL.Convertor();
}
// set global wgs84 list (if provided)
if (Array.isArray(gson) && gson.length > 0) {
GSON_LON_LAT_WSG84 = gson;
}
// init map & polygon
fnInitMap(lon, lat);
if (GSON_LON_LAT_WSG84 && GSON_LON_LAT_WSG84.length > 0) {
fnInitConvertorData(GSON_LON_LAT_WSG84);
}
showHint('地图已初始化');
return true;
} catch (e) {
console.error('initWithData error', e);
return false;
}
};
// 显示调试提示
function showHint(text) {
var el = document.getElementById('hint');
if (!el) return;
el.style.display = 'block';
el.innerText = text;
setTimeout(function(){ el.style.display = 'none'; }, 4000);
}
// ---------------------------
// 页面加载
// ---------------------------
function onLoad() {
// create convertor if possible
if (window.BMapGL && typeof BMapGL.Convertor === 'function') {
convertor = new BMapGL.Convertor();
} else {
console.warn('BMapGL.Convertor not ready yet.');
}
// 创建地图对象(延迟绑定 center等 init 时调用)
map = new BMapGL.Map('container');
map.enableScrollWheelZoom(true);
map.setDisplayOptions({ building: false });
map.addEventListener('click', MapClick);
// 如果 URL 带参数则自动初始化,否则等待宿主调用 initWithData(...)
var ok = tryInitFromUrl();
if (!ok) {
showHint('等待宿主调用 initWithData(...) 初始化地图');
}
}
// ---------------------------
// 点在多边形内判定(二维,只用 lon/lat
// polygon = [[lng,lat], ...]
// point = [lng, lat]
// ---------------------------
function isPointInPolygon(point, polygon) {
const x = point[0];
const y = point[1];
let inside = false;
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
const xi = polygon[i][0], yi = polygon[i][1];
const xj = polygon[j][0], yj = polygon[j][1];
const intersect = ((yi > y) !== (yj > y))
&& (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
}
// 地图点击处理
function MapClick(e) {
try {
if (marker) map.removeOverlay(marker);
marker = new BMapGL.Marker(new BMapGL.Point(e.latlng.lng, e.latlng.lat));
const x = [e.latlng.lng, e.latlng.lat];
let inside = (GSON_LON_LAT_BD09 && GSON_LON_LAT_BD09.length > 0) ? isPointInPolygon(x, GSON_LON_LAT_BD09) : true;
if (!inside) {
//alert("当前选择点位不在区域中!");
notifyHost({type:'point_selected', ok:false, reason:'out_of_polygon', lng:e.latlng.lng, lat:e.latlng.lat});
} else {
map.addOverlay(marker);
// 把 BD09 -> WGS84 转换后的点回传给宿主
fnConvertorBd09ToWgs84Data2(e.latlng.lng, e.latlng.lat);
notifyHost({type:'point_selected', ok:true, lng:e.latlng.lng, lat:e.latlng.lat});
}
} catch (err) {
console.error('MapClick error', err);
}
}
// ---------------------------
// 将 WGS84 多点转换为 BD09 并绘制多边形
// arr: [[lon,lat,...], ...] 注意原 arr GSON_LON_LAT_WSG84顺序是 lon, lat
// ---------------------------
function fnInitConvertorData(arr) {
try {
if (!convertor) convertor = new BMapGL.Convertor();
var points = [];
for (let i = 0; i < arr.length; i++) {
var xi = arr[i][0], yi = arr[i][1];
points.push(new BMapGL.Point(xi, yi));
}
convertor.translate(points, 1, 5, function(res) {
if (!res || !res.points) {
console.warn('convertor.translate returned no points', res);
return;
}
GSON_LON_LAT_BD09 = [];
var list = [];
for (var p = 0; p < res.points.length; p++) {
let item = res.points[p];
GSON_LON_LAT_BD09.push([item.lng, item.lat]);
list.push(new BMapGL.Point(item.lng, item.lat));
}
var polygon = new BMapGL.Polygon(list, {
zIndex: 999,
strokeColor: 'blue',
strokeWeight: 5,
strokeOpacity: 0.5
});
map.addOverlay(polygon);
});
} catch (e) {
console.error('fnInitConvertorData error', e);
}
}
// ---------------------------
// 初始化地图中心longitude, latitude 为 WGS84
// ---------------------------
function fnInitMap(longitude, latitude) {
try {
if (!convertor) convertor = new BMapGL.Convertor();
var ponits = [ new BMapGL.Point(longitude, latitude) ];
convertor.translate(ponits, 1, 5, function(res) {
if (!res || !res.points || res.points.length === 0) {
console.warn('fnInitMap: translate failed', res);
return;
}
var pt = res.points[0];
map.centerAndZoom(new BMapGL.Point(pt.lng, pt.lat), 18);
});
} catch (e) {
console.error('fnInitMap error', e);
}
}
// ---------------------------
// BD09 -> WGS84 JS 版算法),并把结果 post 给宿主
// 注意: bdLat, bdLon 参数顺序(原函数输入顺序)
// 返回 [wgsLat, wgsLon](跟原实现一致)
// ---------------------------
const bd09ToWgs84 = (bdLat, bdLon) => {
const x_pi = (Math.PI * 3000.0) / 180.0;
const x = bdLon - 0.0065;
const y = bdLat - 0.006;
const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
const gcjLon = z * Math.cos(theta);
const gcjLat = z * Math.sin(theta);
let dlat = transformlat(gcjLon - 105.0, gcjLat - 35.0);
let dlng = transformlng(gcjLon - 105.0, gcjLat - 35.0);
const radlat = (gcjLat / 180.0) * Math.PI;
let magic = Math.sin(radlat);
magic = 1 - 0.006693421622965943 * magic * magic;
const sqrtmagic = Math.sqrt(magic);
dlat = (dlat * 180.0) / (((6378245.0 * (1 - 0.006693421622965943)) / (magic * sqrtmagic)) * Math.PI);
dlng = (dlng * 180.0) / ((6378245.0 / sqrtmagic) * Math.cos(radlat) * Math.PI);
const mglat = gcjLat + dlat;
const mglng = gcjLon + dlng;
const wgsLon = gcjLon * 2 - mglng;
const wgsLat = gcjLat * 2 - mglat;
return [wgsLat, wgsLon];
};
const transformlat = (lng, lat) => {
let ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
ret += ((20.0 * Math.sin(6.0 * lng * Math.PI) + 20.0 * Math.sin(2.0 * lng * Math.PI)) * 2.0) / 3.0;
ret += ((20.0 * Math.sin(lat * Math.PI) + 40.0 * Math.sin((lat / 3.0) * Math.PI)) * 2.0) / 3.0;
ret += ((160.0 * Math.sin((lat / 12.0) * Math.PI) + 320 * Math.sin((lat * Math.PI) / 30.0)) * 2.0) / 3.0;
return ret;
};
const transformlng = (lng, lat) => {
let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
ret += ((20.0 * Math.sin(6.0 * lng * Math.PI) + 20.0 * Math.sin(2.0 * lng * Math.PI)) * 2.0) / 3.0;
ret += ((20.0 * Math.sin(lng * Math.PI) + 40.0 * Math.sin((lng / 3.0) * Math.PI)) * 2.0) / 3.0;
ret += ((150.0 * Math.sin((lng / 12.0) * Math.PI) + 300.0 * Math.sin((lng / 30.0) * Math.PI)) * 2.0) / 3.0;
return ret;
};
// ---------------------------
// 使用百度 convertor如果可用把 BD09 点转回 WGS84 并 postMessage 给宿主
// 备用:也会调用 bd09ToWgs84 本地算法
// ---------------------------
function fnConvertorBd09ToWgs84Data2(lng, lat) {
try {
// first try convertor.translate from BMapGL
if (convertor && typeof convertor.translate === 'function') {
var pts = [ new BMapGL.Point(lng, lat) ];
convertor.translate(pts, 5, 1, function(res) {
if (res && res.points && res.points.length > 0) {
var p = res.points[0];
// res.points are in WGS84? depends on convert params; keep compatibility:
notifyHost({type:'converted', longitue: p.lng, latitude: p.lat});
return;
}
// fallback to local algorithm if convertor result absent
var w = bd09ToWgs84(lat, lng);
notifyHost({type:'converted', longitue: w[1], latitude: w[0]});
});
} else {
var w = bd09ToWgs84(lat, lng);
notifyHost({type:'converted', longitue: w[1], latitude: w[0]});
}
} catch (e) {
console.error('fnConvertorBd09ToWgs84Data2 error', e);
var w = bd09ToWgs84(lat, lng);
notifyHost({type:'converted', longitue: w[1], latitude: w[0]});
}
}
// 兼容老方法名
window.fnInitMap = fnInitMap;
window.fnInitConvertorData = fnInitConvertorData;
window.fnConvertorBd09ToWgs84Data2 = fnConvertorBd09ToWgs84Data2;
</script>
</html>

View File

@ -4,7 +4,9 @@ import 'package:qhd_prevention/customWidget/BaiDuMap/BaiduMapWebView.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/services/location_service.dart';
import 'package:qhd_prevention/tools/coord_convert.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:geolocator/geolocator.dart';
@ -37,12 +39,23 @@ class _MapPageState extends State<MapPage> {
_isLoading = true;
_errorMessage = null;
});
LoadingDialogHelper.show(message: '地图加载中');
try {
final LocationResult loc = await LocationService.getCurrentLocation(
timeout: const Duration(seconds: 10),
);
await fetchAndSaveBd09(context);
final prefs = await SharedPreferences.getInstance();
String latitude = prefs.getString('bd_lat') ?? '';
String longitude = prefs.getString('bd_lon') ?? '';
_loadWebView(LocationResult(latitude: latitude, longitude: longitude));
} catch (e, st) {
final prefs = await SharedPreferences.getInstance();
String latitude = prefs.getString('bd_lat') ?? '';
String longitude = prefs.getString('bd_lon') ?? '';
_loadWebView(LocationResult(latitude: latitude, longitude: longitude));
}
}
Future<void> _loadWebView(LocationResult loc) async {
// gson
try {
final parsed = jsonDecode(widget.gson);
@ -55,15 +68,12 @@ class _MapPageState extends State<MapPage> {
debugPrint('解析 gson 失败: $e');
_gsonList = [];
}
if (!mounted) return;
setState(() {
_longitude = loc.longitudeAsDouble;
_latitude = loc.latitudeAsDouble;
});
// WebViewController
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
@ -91,8 +101,6 @@ class _MapPageState extends State<MapPage> {
..setNavigationDelegate(
NavigationDelegate(
onPageFinished: (String url) async {
LoadingDialogHelper.hide();
debugPrint('网页加载完成: $url');
await _injectLocationParams();
},
@ -103,20 +111,12 @@ class _MapPageState extends State<MapPage> {
);
// assets HTML
// await _controller.loadFlutterAsset('assets/map/test_baidu_map.html');
// await _controller.loadFlutterAsset('assets/map/index.html');
await _controller.loadRequest(Uri.parse('http://47.92.102.56:7811/file/fluteightmap/index.html'));
setState(() {
_isLoading = false;
});
} catch (e, st) {
debugPrint('获取位置或初始化失败: $e\n$st');
if (!mounted) return;
setState(() {
_errorMessage = '获取位置失败: ${e.toString()}';
_isLoading = false;
});
}
}
/// window.initWithData(...)

View File

@ -55,7 +55,7 @@ class CustomButton extends StatelessWidget {
} else {
finalTextStyle = TextStyle(
color: isEnabled ? Colors.white : (disabledTextColor ?? Colors.white70),
fontSize: 15,
fontSize: 14,
fontWeight: FontWeight.bold,
);
}
@ -69,7 +69,7 @@ class CustomButton extends StatelessWidget {
onTap: isEnabled ? onPressed : null,
child: Container(
height: height ?? 45, // 45
padding: padding ?? const EdgeInsets.all(8), //
padding: padding ?? const EdgeInsets.all(6), //
margin: margin ?? const EdgeInsets.symmetric(horizontal: 5), //
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderRadius),

View File

@ -4,6 +4,9 @@ import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
import 'package:qhd_prevention/customWidget/full_screen_video_page.dart';
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:video_compress/video_compress.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
import 'package:photo_manager/photo_manager.dart';
@ -563,7 +566,17 @@ class _RepairedPhotoSectionState extends State<RepairedPhotoSection> {
},
onMediaAdded: widget.onMediaAdded,
onMediaRemoved: widget.onMediaRemoved,
onMediaTapped: widget.onMediaTapped,
onMediaTapped: (filePath) {
if (widget.mediaType == MediaType.image) {
presentOpaque(SingleImageViewer(imageUrl: filePath), context);
}else{
showDialog(
context: context,
barrierColor: Colors.black54,
builder: (_) => VideoPlayerPopup(videoUrl:filePath),
);
}
},
//
isEdit: widget.isEdit, //
),

View File

@ -12,7 +12,11 @@ import 'package:flutter/material.dart';
/// if (picked != null) {
/// print('用户选择的时间:$picked');
/// }
enum BottomPickerMode { dateTime, date, dateTimeWithSeconds }
enum BottomPickerMode {
dateTime, //
date, //
dateTimeWithSeconds, //
}
class BottomDateTimePicker {
static Future<DateTime?> showDate(
@ -29,7 +33,8 @@ class BottomDateTimePicker {
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
),
builder: (_) => _InlineDateTimePickerContent(
builder:
(_) => _InlineDateTimePickerContent(
allowFuture: allowFuture,
allowPast: allowPast,
minTimeStr: minTimeStr,
@ -118,8 +123,13 @@ class _InlineDateTimePickerContentState
if (widget.mode == BottomPickerMode.date) {
initial = DateTime(initial.year, initial.month, initial.day);
} else if (widget.mode == BottomPickerMode.dateTime) {
initial = DateTime(initial.year, initial.month, initial.day,
initial.hour, initial.minute);
initial = DateTime(
initial.year,
initial.month,
initial.day,
initial.hour,
initial.minute,
);
}
// dateTimeWithSeconds
@ -135,17 +145,24 @@ class _InlineDateTimePickerContentState
// controllers
yearCtrl = FixedExtentScrollController(
initialItem: years.indexOf(selectedYear).clamp(0, years.length - 1));
initialItem: years.indexOf(selectedYear).clamp(0, years.length - 1),
);
monthCtrl = FixedExtentScrollController(
initialItem: (selectedMonth - 1).clamp(0, months.length - 1));
initialItem: (selectedMonth - 1).clamp(0, months.length - 1),
);
dayCtrl = FixedExtentScrollController(
initialItem: (selectedDay - 1).clamp(0, days.length - 1));
initialItem: (selectedDay - 1).clamp(0, days.length - 1),
);
hourCtrl = FixedExtentScrollController(
initialItem: selectedHour.clamp(0, hours.length - 1));
initialItem: selectedHour.clamp(0, hours.length - 1),
);
minuteCtrl = FixedExtentScrollController(
initialItem: selectedMinute.clamp(0, minutes.length - 1));
secondCtrl = FixedExtentScrollController( //
initialItem: selectedSecond.clamp(0, seconds.length - 1));
initialItem: selectedMinute.clamp(0, minutes.length - 1),
);
secondCtrl = FixedExtentScrollController(
//
initialItem: selectedSecond.clamp(0, seconds.length - 1),
);
// minTime /
WidgetsBinding.instance.addPostFrameCallback((_) {
@ -165,9 +182,9 @@ class _InlineDateTimePickerContentState
try {
final trimmed = s.trim();
final parts = trimmed.split(' ');
final dateParts =
parts[0].split('-').map((e) => int.parse(e)).toList();
final timeParts = (parts.length > 1)
final dateParts = parts[0].split('-').map((e) => int.parse(e)).toList();
final timeParts =
(parts.length > 1)
? parts[1].split(':').map((e) => int.parse(e)).toList()
: [0, 0, 0];
final year = dateParts[0];
@ -208,10 +225,21 @@ class _InlineDateTimePickerContentState
picked = DateTime(selectedYear, selectedMonth, selectedDay);
} else if (isDateTimeOnly) {
picked = DateTime(
selectedYear, selectedMonth, selectedDay, selectedHour, selectedMinute);
selectedYear,
selectedMonth,
selectedDay,
selectedHour,
selectedMinute,
);
} else {
picked = DateTime(selectedYear, selectedMonth, selectedDay,
selectedHour, selectedMinute, selectedSecond);
picked = DateTime(
selectedYear,
selectedMonth,
selectedDay,
selectedHour,
selectedMinute,
selectedSecond,
);
}
// _minTime allowPast
@ -232,8 +260,13 @@ class _InlineDateTimePickerContentState
if (isDateOnly) {
minRef = DateTime(minRef!.year, minRef.month, minRef.day);
} else if (isDateTimeOnly) {
minRef = DateTime(minRef!.year, minRef.month, minRef.day,
minRef.hour, minRef.minute);
minRef = DateTime(
minRef!.year,
minRef.month,
minRef.day,
minRef.hour,
minRef.minute,
);
}
}
} else if (_minTime != null) {
@ -243,8 +276,13 @@ class _InlineDateTimePickerContentState
if (isDateOnly) {
minRef = DateTime(minRef!.year, minRef.month, minRef.day);
} else if (isDateTimeOnly) {
minRef = DateTime(minRef!.year, minRef.month, minRef.day,
minRef.hour, minRef.minute);
minRef = DateTime(
minRef!.year,
minRef.month,
minRef.day,
minRef.hour,
minRef.minute,
);
}
}
@ -363,7 +401,11 @@ class _InlineDateTimePickerContentState
onPressed: () {
DateTime result;
if (isDateOnly) {
result = DateTime(selectedYear, selectedMonth, selectedDay);
result = DateTime(
selectedYear,
selectedMonth,
selectedDay,
);
} else if (isDateTimeOnly) {
result = DateTime(
selectedYear,
@ -411,7 +453,8 @@ class _InlineDateTimePickerContentState
//
_buildPicker(
controller: monthCtrl,
items: months.map((e) => e.toString().padLeft(2, '0')).toList(),
items:
months.map((e) => e.toString().padLeft(2, '0')).toList(),
onSelected: (idx) {
setState(() {
selectedMonth = months[idx];
@ -438,7 +481,8 @@ class _InlineDateTimePickerContentState
if (!isDateOnly)
_buildPicker(
controller: hourCtrl,
items: hours.map((e) => e.toString().padLeft(2, '0')).toList(),
items:
hours.map((e) => e.toString().padLeft(2, '0')).toList(),
onSelected: (idx) {
setState(() {
selectedHour = hours[idx];
@ -450,7 +494,10 @@ class _InlineDateTimePickerContentState
if (!isDateOnly)
_buildPicker(
controller: minuteCtrl,
items: minutes.map((e) => e.toString().padLeft(2, '0')).toList(),
items:
minutes
.map((e) => e.toString().padLeft(2, '0'))
.toList(),
onSelected: (idx) {
setState(() {
selectedMinute = minutes[idx];
@ -463,7 +510,10 @@ class _InlineDateTimePickerContentState
if (widget.mode == BottomPickerMode.dateTimeWithSeconds)
_buildPicker(
controller: secondCtrl,
items: seconds.map((e) => e.toString().padLeft(2, '0')).toList(),
items:
seconds
.map((e) => e.toString().padLeft(2, '0'))
.toList(),
onSelected: (idx) {
setState(() {
selectedSecond = seconds[idx];

View File

@ -2,9 +2,11 @@ import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
class ToastUtil {
///
static void showNormal(BuildContext context, String message, {
ToastGravity gravity = ToastGravity.BOTTOM,
///
static void showNormal(
BuildContext context,
String message, {
ToastGravity gravity = ToastGravity.CENTER, // CENTER
int duration = 2,
}) {
_showToast(
@ -15,9 +17,11 @@ class ToastUtil {
);
}
///
static void showSuccess(BuildContext context, String message, {
ToastGravity gravity = ToastGravity.CENTER,
///
static void showSuccess(
BuildContext context,
String message, {
ToastGravity gravity = ToastGravity.CENTER, // CENTER
int duration = 3,
}) {
_showToast(
@ -29,9 +33,11 @@ class ToastUtil {
);
}
///
static void showError(BuildContext context, String message, {
ToastGravity gravity = ToastGravity.CENTER,
///
static void showError(
BuildContext context,
String message, {
ToastGravity gravity = ToastGravity.CENTER, // CENTER
int duration = 4,
}) {
_showToast(
@ -67,7 +73,7 @@ class ToastUtil {
Fluttertoast.showToast(
msg: message,
toastLength: duration > 2 ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT,
gravity: gravity,
gravity: gravity, // CENTER
backgroundColor: Colors.grey[500],
textColor: Colors.white,
fontSize: 16.0,

View File

@ -19,11 +19,13 @@ class ApiService {
// static const String projectManagerUrl = 'https://pm.qhdsafety.com/zy-projectManage/';
// static const String publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUoHAavCikaZxjlDM6Km8cX+ye78F4oF39AcEfnE1p2Yn9pJ9WFxYZ4Vkh6F8SKMi7k4nYsKceqB1RwG996SvHQ5C3pM3nbXCP4K15ad6QhN4a7lzlbLhiJcyIKszvvK8ncUDw8mVQ0j/2mwxv05yH6LN9OKU6Hzm1ninpWeE+awIDAQAB'
///
// static const String baseFacePath = "https://qaaqwh.qhdsafety.com/whb_stu_face";
static const String baseFacePath =
"https://qaaqwh.qhdsafety.com/whb_stu_face";
"http://192.168.20.240:8500/whb_stu_face/";
///
static const String basePath = "https://qaaqwh.qhdsafety.com/integrated_whb";
// static const String basePath = "https://qaaqwh.qhdsafety.com/integrated_whb";
static const String basePath = "http://192.168.20.240:8500/integrated_whb/";
// static const String basePath = "http://192.168.0.37:8099/api";
///
@ -38,24 +40,6 @@ class ApiService {
'https://pm.qhdsafety.com/zy-projectManage';
// ///
// static const String baseFacePath =
// "https://qaaqwh.qhdsafety.com/whb_stu_face/";
//
// ///
// static const String basePath = "http://192.168.20.240:8500/integrated_whb/";
//
// ///
// static const String baseImgPath = "https://file.zcloudchina.com/YTHFile";
//
// ///
// static const String adminPath =
// "https://qaaqwh.qhdsafety.com/integrated_whb/";
//
// ///
// static const String projectManagerUrl =
// 'https://pm.qhdsafety.com/zy-projectManage';
/// RSA
static const publicKey = '''
-----BEGIN PUBLIC KEY-----

View File

@ -368,12 +368,7 @@ class _DangerManagerDetailPageState extends State<DangerManagerDetailPage> {
'${ApiService.baseImgPath}$path',
)
.toList(),
onMediaTapped: (p) {
presentOpaque(
SingleImageViewer(imageUrl: p),
context,
);
},
onChanged:
(files) => setState(() {
hiddenForm['ysImgs'] =

View File

@ -354,9 +354,6 @@ class _PunishmentManagerDetailPageState extends State<PunishmentManagerDetailPag
initialMediaPaths: _getServerPath(
hiddenForm['ysImgs'],
).map((path) => '${ApiService.baseImgPath}$path').toList(),
onMediaTapped: (p) {
presentOpaque(SingleImageViewer(imageUrl: p), context);
},
onChanged:
(files) => setState(() {
hiddenForm['ysImgs'] =

View File

@ -190,9 +190,6 @@ class _SafeDrawerPageState extends State<SafeDrawerPage> {
isEdit: _isEdit,
isRequired: _isEdit,
initialMediaPaths: _getSelectedImages(),
onMediaTapped: (p) {
presentOpaque(SingleImageViewer(imageUrl: p), context);
},
onChanged:
(files) => setState(() {
hiddenForm['hiddenImgs'] =
@ -222,13 +219,6 @@ class _SafeDrawerPageState extends State<SafeDrawerPage> {
RepairedPhotoSection(
title: '隐患视频',
maxCount: 1,
onMediaTapped: (p) {
showDialog(
context: context,
barrierColor: Colors.black54,
builder: (_) => VideoPlayerPopup(videoUrl:p),
);
},
isEdit: _isEdit,
mediaType: MediaType.video,
initialMediaPaths: _getSelectedVideos(),
@ -680,24 +670,4 @@ class _SafeDrawerPageState extends State<SafeDrawerPage> {
}
}
Future<String> _uploadFile(String path, String type, String id) async {
try {
final r = await ApiService.addImgFiles(path, type, id);
return r['result'] == 'success' ? (r['imgPath'] ?? '') : '';
} catch (_) {
return '';
}
}
Future<Position> _determinePosition() async {
if (!await Geolocator.isLocationServiceEnabled()) throw 'location disabled';
var p = await Geolocator.checkPermission();
if (p == LocationPermission.denied)
p = await Geolocator.requestPermission();
if (p == LocationPermission.denied || p == LocationPermission.deniedForever)
throw 'permission denied';
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
}
}

View File

@ -13,10 +13,13 @@ import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker_hidden_type.dart';
import 'package:qhd_prevention/customWidget/department_picker_two.dart';
import 'package:qhd_prevention/customWidget/full_screen_video_page.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/coord_convert.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../customWidget/photo_picker_row.dart';
import '../../../http/ApiService.dart';
@ -680,12 +683,11 @@ class _CheckInformationOneItemState extends State<CheckInformationOneItem> {
}
//
Position position = await _determinePosition();
String longitude=position.longitude.toString();
String latitude=position.latitude.toString();
await fetchAndSaveBd09(context);
final prefs = await SharedPreferences.getInstance();
String latitude = prefs.getString('bd_lat') ?? '';
String longitude = prefs.getString('bd_lon') ?? '';
try {
// final result = await ApiService.temporaryStorageOfHidden(
// unqualifiedInspectionItemID.isNotEmpty?"edit":"add",widget.item,unqualifiedInspectionItemID,
@ -828,33 +830,6 @@ class _CheckInformationOneItemState extends State<CheckInformationOneItem> {
}
}
Future<Position> _determinePosition() async {
bool serviceEnabled;
LocationPermission permission;
//
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('Location services are disabled.');
}
//
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
return Future.error('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.');
}
//
return await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
}
String truncateText(String text, {int maxLength = 17}) {
if (text.length <= maxLength) return text;

View File

@ -18,7 +18,9 @@ import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/coord_convert.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../customWidget/photo_picker_row.dart';
import '../../../http/ApiService.dart';
@ -256,9 +258,6 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
}
},
onChanged: (List<File> files) {},
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onAiIdentify: () {
// AI
if(_yinHuanImages.isEmpty){
@ -285,13 +284,6 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
onMediaRemoved: (value){
_yinHuanVido.remove(value);
},
onMediaTapped: (path) {
showDialog(
context: context,
barrierColor: Colors.black54,
builder: (_) => VideoPlayerPopup(videoUrl:path),
);
},
onChanged: (List<File> files) {
},
onAiIdentify: () {},
@ -665,12 +657,11 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
hiddenType1=_yinHuanTypeIds[2];
}
//
Position position = await _determinePosition();
String longitude=position.longitude.toString();
String latitude=position.latitude.toString();
await fetchAndSaveBd09(context);
final prefs = await SharedPreferences.getInstance();
String latitude = prefs.getString('bd_lat') ?? '';
String longitude = prefs.getString('bd_lon') ?? '';
try {
@ -720,6 +711,9 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
widget.onClose(hiddenId, _standardController.text.trim());
});
}
}else{
ToastUtil.showNormal(context, "提交失败");
}
} catch (e) {
LoadingDialogHelper.hide();
@ -804,33 +798,6 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
}
}
Future<Position> _determinePosition() async {
bool serviceEnabled;
LocationPermission permission;
//
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('Location services are disabled.');
}
//
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
return Future.error('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.');
}
//
return await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
}
String truncateText(String text, {int maxLength = 17}) {
if (text.length <= maxLength) return text;

View File

@ -12,9 +12,13 @@ import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker_hidden_type.dart';
import 'package:qhd_prevention/customWidget/department_picker_two.dart';
import 'package:qhd_prevention/customWidget/full_screen_video_page.dart';
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/coord_convert.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../customWidget/photo_picker_row.dart';
import '../../../http/ApiService.dart';
@ -518,12 +522,11 @@ class _QuickReportPageState extends State<QuickReportPage> {
hiddenType1=_yinHuanTypeIds[2];
}
//
Position position = await _determinePosition();
String longitude=position.longitude.toString();
String latitude=position.latitude.toString();
await fetchAndSaveBd09(context);
final prefs = await SharedPreferences.getInstance();
String latitude = prefs.getString('bd_lat') ?? '';
String longitude = prefs.getString('bd_lon') ?? '';
try {
Map data = {};
@ -536,7 +539,6 @@ class _QuickReportPageState extends State<QuickReportPage> {
String hiddenId = result['pd']['HIDDEN_ID'] ;
for (int i=0;i<_yinHuanImages.length;i++){
_addImgFiles(_yinHuanImages[i],"3",hiddenId);
}
@ -630,33 +632,5 @@ class _QuickReportPageState extends State<QuickReportPage> {
}
}
Future<Position> _determinePosition() async {
bool serviceEnabled;
LocationPermission permission;
//
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('Location services are disabled.');
}
//
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
return Future.error('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.');
}
//
return await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
}
}

View File

@ -285,9 +285,6 @@ class _NfcCheckDangerDetailState extends State<NfcCheckDangerDetail> {
});
}
},
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onChanged: (v) {},
onAiIdentify: () {
// AI
@ -324,12 +321,6 @@ class _NfcCheckDangerDetailState extends State<NfcCheckDangerDetail> {
});
}
},
onMediaTapped: (path) {
showDialog(
context: context,
barrierColor: Colors.black54,
builder: (_) => VideoPlayerPopup(videoUrl: path),
); },
onMediaAdded: (localPath) {
_videos.add(nfcImgData(path: localPath, id: ''));
},
@ -427,9 +418,6 @@ class _NfcCheckDangerDetailState extends State<NfcCheckDangerDetail> {
initialMediaPaths: zgImgList.map((item) => item.path).toList(),
mediaType: MediaType.image,
isShowAI: false,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaAdded: (localPath) {
zgImgList.add(nfcImgData(path: localPath, id: ''));
},
@ -646,34 +634,4 @@ class _NfcCheckDangerDetailState extends State<NfcCheckDangerDetail> {
}
}
Future<Position> _determinePosition() async {
bool serviceEnabled;
LocationPermission permission;
//
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('Location services are disabled.');
}
//
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
return Future.error('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.',
);
}
//
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
}
}

View File

@ -241,18 +241,12 @@ class _SafecheckAssignmentDetailPageState
RepairedPhotoSection(
title: '隐患视频',
maxCount: 1,
onMediaTapped: (p) {
showDialog(
context: context,
barrierColor: Colors.black54,
builder: (_) => VideoPlayerPopup(videoUrl: p),
);
},
isEdit: false,
mediaType: MediaType.video,
initialMediaPaths: hiddenVideo,
onChanged: (files) {},
onAiIdentify: () {},
),
),
],

View File

@ -125,7 +125,6 @@ class _DefendRecordDetailPageState extends State<DefendRecordDetailPage> {
return Scaffold(
appBar: MyAppbar(title: '申辩记录'),
body: SafeArea(
child: Expanded(
child: ListView.builder(
itemCount: _list.length,
itemBuilder: (context, index) {
@ -134,7 +133,6 @@ class _DefendRecordDetailPageState extends State<DefendRecordDetailPage> {
},
),
),
),
);
}
}

View File

@ -220,12 +220,6 @@ class _SafeCheckDrawerPageState extends State<SafeCheckDrawerPage> {
isEdit: _isEdit,
isRequired: _isEdit,
initialMediaPaths: _getSelectedImages(),
onMediaTapped: (p) {
presentOpaque(
SingleImageViewer(imageUrl: p),
context,
);
},
onChanged:
(files) => setState(() {
hiddenForm['hiddenImgs'] =
@ -255,13 +249,6 @@ class _SafeCheckDrawerPageState extends State<SafeCheckDrawerPage> {
RepairedPhotoSection(
title: '隐患视频',
maxCount: 1,
onMediaTapped: (p) {
showDialog(
context: context,
barrierColor: Colors.black54,
builder: (_) => VideoPlayerPopup(videoUrl: p),
);
},
isEdit: _isEdit,
mediaType: MediaType.video,
initialMediaPaths: _getSelectedVideos(),

View File

@ -133,6 +133,9 @@ class _TeamSafetyCommitmentApplyState extends State<TeamSafetyCommitmentApply> {
isEditable: true,
controller: _controller5,
text: '',
onChanged: (v) {
}
),
const Divider(),

View File

@ -8,6 +8,8 @@ import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/scan_page.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/services/auth_service.dart';
import 'package:qhd_prevention/services/location_service.dart';
import 'package:qhd_prevention/tools/coord_convert.dart';
import 'package:qhd_prevention/tools/update/update_dialogs.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
@ -185,10 +187,12 @@ class HomePageState extends State<HomePage> {
// 使
_initialLoad();
BadgeManager().initAllModules();
}
/// loading
Future<void> _initialLoad() async {
///
final data = await ApiService.getListData();
if (data['result'] == 'success') {
@ -239,6 +243,8 @@ class HomePageState extends State<HomePage> {
// + hiddenList loading
await _fetchData();
await _fetchHiddenList(showLoading: hiddenList.isEmpty);
await fetchAndSaveBd09(context);
}
Future<void> _onRefresh() async {

View File

@ -1,7 +1,9 @@
import 'package:flutter/material.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/coord_convert.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:geolocator/geolocator.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../http/ApiService.dart';
import '../../../tools/h_colors.dart';
@ -64,9 +66,13 @@ class _RiskDetailPageState extends State<RiskDetailPage> {
Future<void> _addCoordinate() async {
try {
Position position = await _determinePosition();
//
await fetchAndSaveBd09(context);
final prefs = await SharedPreferences.getInstance();
String latitude = prefs.getString('bd_lat') ?? '';
String longitude = prefs.getString('bd_lon') ?? '';
final result = await ApiService.addCoordinate( widget.itemData["IDENTIFICATIONPARTS_ID"],
position.longitude.toString(),position.latitude.toString());
longitude,latitude);
if (result['result'] == 'success') {
setState(() {
_showMessage('提交成功');
@ -391,34 +397,6 @@ class _RiskDetailPageState extends State<RiskDetailPage> {
);
}
Future<Position> _determinePosition() async {
bool serviceEnabled;
LocationPermission permission;
//
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('Location services are disabled.');
}
//
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
return Future.error('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.');
}
//
return await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
}
void _showMessage(String msg) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg)));
}

View File

@ -288,7 +288,7 @@ class _StudyMyTaskPageState extends State<StudyMyTaskPage> with RouteAware {
],
),
Wrap(
spacing: 10,
spacing: 5,
children: [
//
if (studyState >= 2 &&
@ -317,7 +317,8 @@ class _StudyMyTaskPageState extends State<StudyMyTaskPage> with RouteAware {
CustomButton(
height: 36,
text: "立即学习",
padding: EdgeInsets.symmetric(horizontal: 18),
margin: const EdgeInsets.symmetric(horizontal: 2),
padding: EdgeInsets.symmetric(horizontal: 15),
borderRadius: 18,
backgroundColor: Colors.blue,
onPressed: () {
@ -338,7 +339,9 @@ class _StudyMyTaskPageState extends State<StudyMyTaskPage> with RouteAware {
CustomButton(
height: 36,
text: "立即考试",
padding: EdgeInsets.symmetric(horizontal: 18),
margin: const EdgeInsets.symmetric(horizontal: 2),
padding: EdgeInsets.symmetric(horizontal: 15),
borderRadius: 18,
backgroundColor: Colors.green,
onPressed:
@ -349,7 +352,9 @@ class _StudyMyTaskPageState extends State<StudyMyTaskPage> with RouteAware {
CustomButton(
height: 36,
text: "考试详情",
padding: EdgeInsets.symmetric(horizontal: 18),
margin: const EdgeInsets.symmetric(horizontal: 2),
padding: EdgeInsets.symmetric(horizontal: 15),
borderRadius: 18,
backgroundColor: Colors.green,
onPressed: () {

View File

@ -62,7 +62,8 @@ class _StudyScorePageState extends State<StudyScorePage> {
int _toInt(dynamic value, {required int defaultValue}) {
if (value is int) return value;
if (value is String) {
return int.tryParse(value) ?? defaultValue;
int score = int.parse(value);
return score;
}
return defaultValue;
}
@ -115,8 +116,7 @@ class _StudyScorePageState extends State<StudyScorePage> {
}
//
int score = _toInt(item['STAGEEXAMSCORE'], defaultValue: -1);
String scoreText = score >= 0 ? '$score' : '';
String scoreText = item['STAGEEXAMSCORE'] == '-1' ? '' : item['STAGEEXAMSCORE'];
return Card(
color: Colors.white,

View File

@ -115,6 +115,7 @@ class _TakeExamPageState extends State<TakeExamPage> {
return CustomAlertDialog.showAlert(
context,
title: '温馨提示',
content: content,
confirmText: '确认'
);
@ -212,7 +213,8 @@ class _TakeExamPageState extends State<TakeExamPage> {
cancelText: '',
confirmText: '确定',
);
if (ok) {}
Navigator.of(context).pop();
}
}
@ -269,7 +271,7 @@ class _TakeExamPageState extends State<TakeExamPage> {
Expanded(
child: Text(
q.options[key] ?? '',
style: const TextStyle(fontSize: 16),
style: const TextStyle(fontSize: 15),
),
),
],
@ -321,7 +323,7 @@ class _TakeExamPageState extends State<TakeExamPage> {
'考试科目:${info['EXAMNAME'] ?? ''}',
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
@ -330,7 +332,7 @@ class _TakeExamPageState extends State<TakeExamPage> {
'当前试题 ${current + 1}/${questions.length}',
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontSize: 15,
),
),
const SizedBox(height: 8),
@ -338,7 +340,7 @@ class _TakeExamPageState extends State<TakeExamPage> {
'考试剩余时间:$_formattedTime',
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontSize: 15,
),
),
],
@ -348,18 +350,35 @@ class _TakeExamPageState extends State<TakeExamPage> {
],
),
const SizedBox(height: 16),
if (q != null) ...[
// ============= =============
if (q != null)
//
Expanded(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${current + 1}. ${q.questionDry} ${questionTypeMap[q.questionType] ?? ''}',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
fontWeight: FontWeight.w500,
fontSize: 15,
),
),
const SizedBox(height: 16),
_buildOptions(q),
//
const SizedBox(height: 24),
],
const Spacer(),
),
),
)
else
//
const Expanded(child: SizedBox()),
const SizedBox(height: 8),
Row(
children: [
if (current > 0)

View File

@ -192,7 +192,7 @@ class _VideoStudyDetailPageState extends State<VideoStudyDetailPage> {
children: [
Text(
'考试科目: ${paperInfo['EXAMNAME']}',
style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold),
style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold),
),
Padding(padding: EdgeInsets.symmetric(horizontal: 15), child: Divider(color: Colors.white30, height: 20,),),
Text(
@ -210,7 +210,7 @@ class _VideoStudyDetailPageState extends State<VideoStudyDetailPage> {
if (q != null) ...[
Text(
'${current + 1}. ${q.questionDry} ${questionTypeMap[q.questionType]}',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
style: TextStyle(fontSize: 16),
),
SizedBox(height: 16),
_buildOptions(q),

View File

@ -329,9 +329,6 @@ class _DangerousOptionsPageState extends State<DangerousOptionsPage> {
.toList(),
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere((e) => e.localPath == path);
_onImageRemoved(item);

View File

@ -324,9 +324,6 @@ class _HotworkAqjdDetailState extends State<HotworkAqjdDetail> {
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -476,10 +476,10 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
{'value': _locationController.text.trim(), 'message': '请填写动火地点及部位'},
{'value': _methodController.text.trim(), 'message': '请填写动火方式'},
{'value': _hotworkPersonController.text.trim(), 'message': '请填写动火人及证书编号'},
{
'value': _relatedController.text.trim(),
'message': '请输入关联的其他特殊作业及安全作业票编号',
},
// {
// 'value': _relatedController.text.trim(),
// 'message': '请输入关联的其他特殊作业及安全作业票编号',
// },
{'value': _riskController.text.trim(), 'message': '请填写风险辨识结果'},
];
final level = pd['WORK_LEVEL'] ?? '';

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/full_screen_video_page.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/tools/tools.dart';
@ -199,7 +200,7 @@ class _HotworkYsgdDetailState extends State<HotworkYsgdDetail> {
title: '作废原因',
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定'
confirmText: '确定',
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
@ -243,7 +244,7 @@ class _HotworkYsgdDetailState extends State<HotworkYsgdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
} else {
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
@ -388,9 +389,6 @@ class _HotworkYsgdDetailState extends State<HotworkYsgdDetail> {
horizontalPadding: 0,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -317,9 +317,6 @@ class _CutroadAqjdDetailState extends State<CutroadAqjdDetail> {
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -281,10 +281,10 @@ class _CutroadApplyDetailState extends State<CutroadApplyDetail> {
{'value': _unitController.text.trim(), 'message': '请输入涉及相关单位(部门)'},
{'value': _contentController.text.trim(), 'message': '请输入断路原因'},
{
'value': _relatedController.text.trim(),
'message': '请输入关联的其他特殊作业及安全作业票编号',
},
// {
// 'value': _relatedController.text.trim(),
// 'message': '请输入关联的其他特殊作业及安全作业票编号',
// },
{'value': _riskController.text.trim(), 'message': '请填写风险辨识结果'},
];
///

View File

@ -380,12 +380,6 @@ class _CutroadYsgdDetailState extends State<CutroadYsgdDetail> {
horizontalPadding: 0,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -328,9 +328,6 @@ setState(() {
horizontalPadding: 0,
isRequired: true,
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere((e) => e.localPath == path);
_onImageRemoved(item);

View File

@ -317,9 +317,6 @@ class _BreakgroundAqjdDetailState extends State<BreakgroundAqjdDetail> {
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -420,10 +420,10 @@ class _BreakgroundApplyDetailState extends State<BreakgroundApplyDetail> {
final textRules = <Map<String, dynamic>>[
{'value': _locationController.text.trim(), 'message': '请输入作业地点'},
{'value': _contentController.text.trim(), 'message': '请输入作业内容'},
{
'value': _relatedController.text.trim(),
'message': '请输入关联的其他特殊作业及安全作业票编号',
},
// {
// 'value': _relatedController.text.trim(),
// 'message': '请输入关联的其他特殊作业及安全作业票编号',
// },
{'value': _riskController.text.trim(), 'message': '请输入风险辨识结果'},
];

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/full_screen_video_page.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/tools/tools.dart';
@ -382,9 +383,6 @@ class _BreakgroundYsgdDetailState extends State<BreakgroundYsgdDetail> {
horizontalPadding: 0,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -353,9 +353,6 @@ class _BreakgroundZyrDetailState extends State<BreakgroundZyrDetail> {
isShowNum: false,
isRequired: true,
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = workImages.firstWhere(
(e) => e.localPath == path,

View File

@ -317,9 +317,6 @@ class _HoistworkAqjdDetailState extends State<HoistworkAqjdDetail> {
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -428,10 +428,10 @@ class _HoistworkApplyDetailState extends State<HoistworkApplyDetail> {
{'value': _nameController.text.trim(), 'message': '请输入吊具名称'},
{'value': _hightController.text.trim(), 'message': '请输入吊物质量(吨)'},
{'value': _contentController.text.trim(), 'message': '请输入吊物内容'},
{
'value': _relatedController.text.trim(),
'message': '请输入关联的其他特殊作业及安全作业票编号',
},
// {
// 'value': _relatedController.text.trim(),
// 'message': '请输入关联的其他特殊作业及安全作业票编号',
// },
{'value': _riskController.text.trim(), 'message': '请输入风险辨识结果'},
];
final level = pd['WORK_LEVEL'] ?? '';

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/full_screen_video_page.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/tools/tools.dart';
@ -199,7 +200,7 @@ class _HoistworkYsgdDetailState extends State<HoistworkYsgdDetail> {
title: '作废原因',
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定'
confirmText: '确定',
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
@ -243,7 +244,7 @@ class _HoistworkYsgdDetailState extends State<HoistworkYsgdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
} else {
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
@ -382,9 +383,6 @@ class _HoistworkYsgdDetailState extends State<HoistworkYsgdDetail> {
horizontalPadding: 0,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -317,9 +317,6 @@ class _HighworkAqjdDetailState extends State<HighworkAqjdDetail> {
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -428,10 +428,10 @@ class _HighworkApplyDetailState extends State<HighworkApplyDetail> {
{'value': _hightController.text.trim(), 'message': '请填写高度'},
{'value': _contentController.text.trim(), 'message': '请填写作业内容'},
{
'value': _relatedController.text.trim(),
'message': '请输入关联的其他特殊作业及安全作业票编号',
},
// {
// 'value': _relatedController.text.trim(),
// 'message': '请输入关联的其他特殊作业及安全作业票编号',
// },
{'value': _riskController.text.trim(), 'message': '请填写风险辨识结果'},
];
final level = pd['WORK_LEVEL'] ?? '';

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/full_screen_video_page.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/tools/tools.dart';
@ -199,7 +200,7 @@ class _HighworkYsgdDetailState extends State<HighworkYsgdDetail> {
title: '作废原因',
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定'
confirmText: '确定',
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
@ -243,7 +244,7 @@ class _HighworkYsgdDetailState extends State<HighworkYsgdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
} else {
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
@ -382,9 +383,6 @@ class _HighworkYsgdDetailState extends State<HighworkYsgdDetail> {
horizontalPadding: 0,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -324,9 +324,6 @@ class _ElectricityAqjdDetailState extends State<ElectricityAqjdDetail> {
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -441,7 +441,10 @@ class _ElectricityApplyDetailState extends State<ElectricityApplyDetail> {
'message': '请输入负责人电工号',
},
{'value': _VController.text.trim(), 'message': '请输入工作电压'},
{'value': _relatedController.text.trim(), 'message': '请输入关联的其他特殊作业及安全作业票编号'},
// {
// 'value': _relatedController.text.trim(),
// 'message': '请输入关联的其他特殊作业及安全作业票编号',
// },
{'value': _riskController.text.trim(), 'message': '请填写风险辨识结果'},

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/full_screen_video_page.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/tools/tools.dart';
@ -199,7 +200,7 @@ class _ElectricityYsgdDetailState extends State<ElectricityYsgdDetail> {
title: '作废原因',
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定'
confirmText: '确定',
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
@ -243,7 +244,7 @@ class _ElectricityYsgdDetailState extends State<ElectricityYsgdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
} else {
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
@ -388,9 +389,6 @@ class _ElectricityYsgdDetailState extends State<ElectricityYsgdDetail> {
horizontalPadding: 0,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -320,9 +320,6 @@ class _BlindboardAqjdDetailState extends State<BlindboardAqjdDetail> {
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -326,9 +326,6 @@ setState(() {
horizontalPadding: 0,
isRequired: true,
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere((e) => e.localPath == path);
_onImageRemoved(item);

View File

@ -28,6 +28,7 @@ enum EditUserType {
CONFIRM('作业负责人单位', '作业负责人', true),
LEADER('所在单位', '所在单位负责人', true),
WORK_START('实际作业开始负责人单位', '实际作业开始负责人', true),
WORK_END('作业结束负责人单位', '作业结束负责人', true),
ACCEPT('验收部门', '验收部门负责人', true);
///
@ -430,10 +431,13 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
{'value': _temperatureController.text.trim(), 'message': '请输入温度'},
{'value': _pressureController.text.trim(), 'message': '请输入压力'},
{
'value': _relatedController.text.trim(),
'message': '请输入关联的其他特殊作业及安全作业票编号',
},
// {
// 'value': _relatedController.text.trim(),
// 'm// {
// 'value': _relatedController.text.trim(),
// 'message': '请输入关联的其他特殊作业及安全作业票编号',
// },',
// },
{'value': _riskController.text.trim(), 'message': '请填写风险辨识结果'},
];
final level = pd['WORK_TYPE'] ?? '';
@ -449,6 +453,7 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
EditUserType.WORKSHOP,
EditUserType.WORK_USER,
EditUserType.WORK_START,
EditUserType.WORK_END,
EditUserType.ACCEPT,
];
if (status == '1') {
@ -666,6 +671,26 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
],
),
),
SizedBox(height: 15),
_card(
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
_chooseItem(EditUserType.WORK_END),
Divider(),
Row(
children: [
SizedBox(width: 12),
Text(
'友情提示:负责填写作业实际结束时间',
style: TextStyle(color: Colors.red),
),
],
),
SizedBox(height: 5),
],
),
),
SizedBox(height: 15),
_card(_chooseItem(EditUserType.ACCEPT)),

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/full_screen_video_page.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/tools/tools.dart';
@ -190,7 +191,7 @@ class _BlindboardYsgdDetailState extends State<BlindboardYsgdDetail> {
title: '作废原因',
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定'
confirmText: '确定',
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
@ -234,7 +235,7 @@ class _BlindboardYsgdDetailState extends State<BlindboardYsgdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
} else {
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
@ -375,9 +376,6 @@ class _BlindboardYsgdDetailState extends State<BlindboardYsgdDetail> {
horizontalPadding: 0,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -328,9 +328,6 @@ class _SpaceworkAqjdDetailState extends State<SpaceworkAqjdDetail> {
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -440,10 +440,10 @@ class _SpaceworkApplyDetailState extends State<SpaceworkApplyDetail> {
{'value': _spaceNameController.text.trim(), 'message': '请确认受限空间名称不能为空'},
{'value': _jzController.text.trim(), 'message': '请输入受限空间内原有介质名称'},
{'value': pd['LIMITSPACE_NUMBER'], 'message': '请确认受限空间编号不能为空'},
{
'value': _relatedController.text.trim(),
'message': '请输入关联的其他特殊作业及安全作业票编号',
},
// {
// 'value': _relatedController.text.trim(),
// 'message': '请输入关联的其他特殊作业及安全作业票编号',
// },
{'value': _riskController.text.trim(), 'message': '请填写风险辨识结果'},
];

View File

@ -1,4 +1,5 @@
import 'dart:io';
import 'package:qhd_prevention/customWidget/full_screen_video_page.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/sxkj_work/qtfx_work_detail/spacework_gas_list.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
@ -200,7 +201,7 @@ class _SpaceworkYsgdDetailState extends State<SpaceworkYsgdDetail> {
title: '作废原因',
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定'
confirmText: '确定',
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
@ -244,7 +245,7 @@ class _SpaceworkYsgdDetailState extends State<SpaceworkYsgdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
} else {
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
@ -392,9 +393,6 @@ class _SpaceworkYsgdDetailState extends State<SpaceworkYsgdDetail> {
horizontalPadding: 0,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -7,9 +7,11 @@ import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/http/ApiService.dart';
import 'package:qhd_prevention/pages/app/Danger_paicha/danger_image_updata_page.dart';
import 'package:qhd_prevention/pages/app/Danger_paicha/hazard_registration_page.dart';
import 'package:qhd_prevention/tools/coord_convert.dart';
import 'package:qhd_prevention/tools/h_colors.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:shared_preferences/shared_preferences.dart';
class DangerProjectPage extends StatefulWidget {
const DangerProjectPage(this.item, this.type, this.checkrecordId, {super.key});
@ -533,9 +535,11 @@ class _DangerProjectPageState extends State<DangerProjectPage> {
}
Future<void> _submitInvestigationItems() async {
Position position = await _determinePosition();
String longitude = position.longitude.toString();
String latitude = position.latitude.toString();
//
await fetchAndSaveBd09(context);
final prefs = await SharedPreferences.getInstance();
String latitude = prefs.getString('bd_lat') ?? '';
String longitude = prefs.getString('bd_lon') ?? '';
upDataItemList.clear();
bool hasNoSelectItem = false;
@ -610,30 +614,6 @@ class _DangerProjectPageState extends State<DangerProjectPage> {
}
}
Future<Position> _determinePosition() async {
bool serviceEnabled;
LocationPermission permission;
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('Location services are disabled.');
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
return Future.error('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
return Future.error('Location permissions are permanently denied, we cannot request permissions.');
}
return await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
}
String truncateText(String text, {int maxLength = 17}) {
if (text.length <= maxLength) return text;
return '${text.substring(0, maxLength)}...';

View File

@ -39,10 +39,10 @@ class LoginPage extends StatefulWidget {
class _LoginPageState extends State<LoginPage> {
final TextEditingController _phoneController = TextEditingController(
text: '13293211008',
// text: '13293211008',
);
final TextEditingController _passwordController = TextEditingController(
text: 'Zsaq@123456',
// text: 'Zsaq@123456',
);
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
String _errorMessage = '';

View File

@ -0,0 +1,229 @@
// lib/utils/location_helper.dart
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:shared_preferences/shared_preferences.dart';
/// ============ WGS84/GCJ02/BD09 ============
const double _pi = 3.1415926535897932384626;
const double _xPi = _pi * 3000.0 / 180.0;
const double _a = 6378245.0;
const double _ee = 0.006693421622965943;
///
bool _outOfChina(double lat, double lon) {
if (lon < 72.004 || lon > 137.8347) return true;
if (lat < 0.8293 || lat > 55.8271) return true;
return false;
}
double _transformLat(double x, double y) {
double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(x.abs());
ret += (20.0 * sin(6.0 * x * _pi) + 20.0 * sin(2.0 * x * _pi)) * 2.0 / 3.0;
ret += (20.0 * sin(y * _pi) + 40.0 * sin(y / 3.0 * _pi)) * 2.0 / 3.0;
ret += (160.0 * sin(y / 12.0 * _pi) + 320.0 * sin(y * _pi / 30.0)) * 2.0 / 3.0;
return ret;
}
double _transformLon(double x, double y) {
double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(x.abs());
ret += (20.0 * sin(6.0 * x * _pi) + 20.0 * sin(2.0 * x * _pi)) * 2.0 / 3.0;
ret += (20.0 * sin(x * _pi) + 40.0 * sin(x / 3.0 * _pi)) * 2.0 / 3.0;
ret += (150.0 * sin(x / 12.0 * _pi) + 300.0 * sin(x / 30.0 * _pi)) * 2.0 / 3.0;
return ret;
}
/// WGS84 -> GCJ02
List<double> wgs84ToGcj02(double lat, double lon) {
if (_outOfChina(lat, lon)) return [lat, lon];
double dLat = _transformLat(lon - 105.0, lat - 35.0);
double dLon = _transformLon(lon - 105.0, lat - 35.0);
double radLat = lat / 180.0 * _pi;
double magic = sin(radLat);
magic = 1 - _ee * magic * magic;
double sqrtMagic = sqrt(magic);
dLat = (dLat * 180.0) / ((_a * (1 - _ee)) / (magic * sqrtMagic) * _pi);
dLon = (dLon * 180.0) / ((_a / sqrtMagic) * cos(radLat) * _pi);
double mgLat = lat + dLat;
double mgLon = lon + dLon;
return [mgLat, mgLon];
}
/// GCJ02 -> BD09
List<double> gcj02ToBd09(double lat, double lon) {
double x = lon;
double y = lat;
double z = sqrt(x * x + y * y) + 0.00002 * sin(y * _xPi);
double theta = atan2(y, x) + 0.000003 * cos(x * _xPi);
double bdLon = z * cos(theta) + 0.0065;
double bdLat = z * sin(theta) + 0.006;
return [bdLat, bdLon];
}
/// WGS84 -> BD09 WGS84->GCJ02 GCJ02->BD09
List<double> wgs84ToBd09(double lat, double lon) {
final gcj = wgs84ToGcj02(lat, lon);
return gcj02ToBd09(gcj[0], gcj[1]);
}
/// ============ ============
///
const Duration _locationTimeout = Duration(seconds: 10);
/// BD09
/// [bdLat, bdLon]
Future<List<double>> getBd09FromGeolocator({
LocationAccuracy accuracy = LocationAccuracy.high,
}) async {
// 1.
LocationPermission permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
//
throw Exception('定位权限被用户拒绝');
}
}
if (permission == LocationPermission.deniedForever) {
//
throw Exception('定位权限被永久拒绝');
}
// 2. GPS/
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
throw Exception('定位服务未开启');
}
// 3. getCurrentPosition
Position? position;
try {
position = await Geolocator.getCurrentPosition(desiredAccuracy: accuracy)
.timeout(_locationTimeout);
} on TimeoutException catch (_) {
position = null;
} catch (_) {
position = null;
}
// 4. getLastKnownPosition
if (position == null) {
try {
position = await Geolocator.getLastKnownPosition();
} catch (_) {
position = null;
}
}
// 5. Android forceAndroidLocationManager/
if (position == null) {
try {
position = await Geolocator.getCurrentPosition(
desiredAccuracy: accuracy,
forceAndroidLocationManager: true,
).timeout(_locationTimeout);
} catch (_) {
position = null;
}
}
// 6. ->
if (position == null) {
throw Exception('无法获取位置信息,请检查设备定位设置或权限');
}
// 7. WGS84 -> BD09 [bdLat, bdLon]
final bd = wgs84ToBd09(position.latitude, position.longitude);
return bd;
}
/// ============ ============
String _mapExceptionToChineseMessage(Object e) {
final msg = e?.toString() ?? '';
if (msg.contains('定位权限被用户拒绝') || msg.contains('Location permissions are denied') || msg.contains('denied')) {
return '定位权限被拒绝,请允许应用获取定位权限。';
}
if (msg.contains('定位权限被永久拒绝') || msg.contains('deniedForever') || msg.contains('permanently denied')) {
return '定位权限被永久拒绝,请到系统设置手动开启定位权限。';
}
if (msg.contains('定位服务未开启') || msg.contains('Location services are disabled')) {
return '设备定位功能未开启,请打开系统定位后重试。';
}
if (msg.contains('无法获取位置信息') || msg.contains('无法获取位置信息')) {
return '无法获取有效定位,请检查网络/GPS并重试可尝试切换到高精度模式';
}
//
return '定位失败:${msg.replaceAll('Exception: ', '')}';
}
/// ============ BD09 UI / ============
/// await fetchAndSaveBd09(context);
Future<void> fetchAndSaveBd09(BuildContext context) async {
// loading LoadingDialogHelper
// loading
try {
// BD09
final List<double> bd = await getBd09FromGeolocator();
final bdLat = bd[0];
final bdLon = bd[1];
// SharedPreferences便
final prefs = await SharedPreferences.getInstance();
await prefs.setString('bd_lat', bdLat.toString());
await prefs.setString('bd_lon', bdLon.toString());
//
// ToastUtil.showNormal(context, '定位成功:$bdLat, $bdLon');
} on Exception catch (e) {
final msg = e.toString();
// ->
if (msg.contains('定位权限被永久拒绝') || msg.contains('deniedForever') || msg.contains('permanently denied')) {
final open = await CustomAlertDialog.showConfirm(
context,
title: '定位权限',
content: '定位权限被永久拒绝,需要手动到应用设置开启定位权限,是否现在打开设置?',
cancelText: '取消',
confirmText: '去设置',
);
if (open == true) {
await Geolocator.openAppSettings();
}
}
// ->
else if (msg.contains('定位服务未开启') || msg.contains('Location services are disabled')) {
final open = await CustomAlertDialog.showConfirm(
context,
title: '打开定位',
content: '检测到设备定位服务未开启,是否打开系统定位设置?',
cancelText: '取消',
confirmText: '去打开',
);
if (open == true) {
await Geolocator.openLocationSettings();
}
}
// -> toast
else {
final userMsg = _mapExceptionToChineseMessage(e);
if (userMsg.isNotEmpty) {
// ToastUtil.showError(context, userMsg);
} else {
// ToastUtil.showError(context, '定位失败:${e.toString()}');
}
}
} catch (e) {
//
// ToastUtil.showError(context, '发生未知错误:${e.toString()}');
} finally {
}
}

View File

@ -495,3 +495,4 @@ class NativeOrientation {
}
}
}

View File

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 2.1.2+2
version: 2.1.2+3
environment:
sdk: ^3.7.0
@ -86,7 +86,6 @@ dependencies:
webview_flutter: ^4.4.0
path_provider: ^2.0.1
camera: ^0.11.2
#富文本查看
flutter_html: ^3.0.0