八项作业弹窗逻辑改动前保存

main
hs 2025-08-21 16:44:24 +08:00
parent 421d71f7c9
commit 87b1f80d3d
187 changed files with 5598 additions and 1428 deletions

View File

@ -30,7 +30,7 @@ android {
defaultConfig {
applicationId = "com.zhuoyun.qhdprevention.qhd_prevention"
minSdk = flutter.minSdkVersion
minSdk = 22
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName

View File

@ -1,11 +1,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 定位 -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- 定位权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <!-- 后台定位 -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!-- 相册 -->
<!-- 相册权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <!-- Android 13+ -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 12及以下 -->
@ -19,57 +20,56 @@
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<!-- 通知 -->
<!-- 无需权限,但需创建通知渠道 -->
<!-- 蓝牙 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- Android 12+ -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <!-- Android 12+ -->
<!-- 本地网络 -->
<!-- 网络 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<!-- 存储(非相册文件) -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 仅支持旧版 -->
<!-- 存储兼容旧版Android 11+ 基本无效) -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29"
tools:replace="android:maxSdkVersion" />
<!-- NFC -->
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />
<!-- 角标 -->
<!-- 安装 APK -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!-- 角标适配不同厂商 -->
<!-- Samsung -->
<uses-permission android:name="com.sec.android.provider.badge.permission.READ"/>
<uses-permission android:name="com.sec.android.provider.badge.permission.WRITE"/>
<!-- Huawei -->
<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE" />
<uses-permission android:name="com.huawei.android.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="com.huawei.android.launcher.permission.WRITE_SETTINGS" />
<!-- HTC -->
<uses-permission android:name="com.htc.launcher.permission.READ_SETTINGS"/>
<uses-permission android:name="com.htc.launcher.permission.UPDATE_SHORTCUT"/>
<!-- Apex -->
<uses-permission android:name="com.anddoes.launcher.permission.UPDATE_COUNT"/>
<!-- Sony -->
<uses-permission android:name="com.sonyericsson.home.permission.BROADCAST_BADGE"/>
<uses-permission android:name="com.sonymobile.home.permission.PROVIDER_INSERT_BADGE"/>
<!-- Solid -->
<uses-permission android:name="com.majeur.launcher.permission.UPDATE_BADGE"/>
<application
android:label="qhd_prevention"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true"
android:enableOnBackInvokedCallback="true"
>
android:enableOnBackInvokedCallback="true">
<activity
android:name=".MainActivity"
android:exported="true"
@ -79,34 +79,40 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<!-- FileProvider 配置 -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.zhuoyun.qhdprevention.qhd_prevention.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<!-- Flutter 插件需要 -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<!-- Android 11+ package visibility -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
<!-- 允许安装器查询 -->
<package android:name="com.android.packageinstaller" />
</queries>
</manifest>

View File

@ -1,5 +1,60 @@
package com.zhuoyun.qhdprevention.qhd_prevention
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import androidx.core.content.FileProvider
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import java.io.File
class MainActivity : FlutterActivity()
class MainActivity: FlutterActivity() {
private val CHANNEL = "app.install"
private val REQ_INSTALL_UNKNOWN = 9999
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
when (call.method) {
"installApk" -> {
val path = call.argument<String>("path")
if (path == null) {
result.error("NO_PATH", "no path provided", null)
return@setMethodCallHandler
}
installApk(path, result)
}
else -> result.notImplemented()
}
}
}
private fun installApk(path: String, result: MethodChannel.Result) {
val file = File(path)
if (!file.exists()) {
result.error("NO_FILE", "file not exist", null)
return
}
// Android 8.0+ 需要允许安装未知来源
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!packageManager.canRequestPackageInstalls()) {
// 引导用户去设置允许安装未知来源(你可以在 Flutter 侧提示用户)
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:$packageName"))
startActivity(intent)
result.error("NEED_INSTALL_PERMISSION", "need install permission", null)
return
}
}
val apkUri: Uri = FileProvider.getUriForFile(this, "$packageName.fileprovider", file)
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivity(intent)
result.success(true)
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 允许访问 app 的缓存目录 -->
<cache-path name="cache" path="." />
<!-- 允许访问 app 的 files 目录 -->
<files-path name="files" path="." />
<!-- 允许访问外部下载目录 -->
<external-path name="download" path="." />
</paths>

View File

@ -1,3 +1,3 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true
android.enableJetifier=true

View File

@ -0,0 +1,380 @@
<!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

@ -1,9 +1,21 @@
PODS:
- BaiduMapKit/Base (6.6.4)
- BaiduMapKit/Map (6.6.4):
- BaiduMapKit/Base
- BaiduMapKit/Utils (6.6.4):
- BaiduMapKit/Base
- camera_avfoundation (0.0.1):
- Flutter
- connectivity_plus (0.0.1):
- Flutter
- Flutter (1.0.0)
- flutter_baidu_mapapi_base (3.9.0):
- BaiduMapKit/Utils (= 6.6.4)
- Flutter
- flutter_baidu_mapapi_map (3.9.0):
- BaiduMapKit/Map (= 6.6.4)
- Flutter
- flutter_baidu_mapapi_base
- flutter_new_badger (0.0.1):
- Flutter
- fluttertoast (0.0.2):
@ -46,6 +58,8 @@ DEPENDENCIES:
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- Flutter (from `Flutter`)
- flutter_baidu_mapapi_base (from `.symlinks/plugins/flutter_baidu_mapapi_base/ios`)
- flutter_baidu_mapapi_map (from `.symlinks/plugins/flutter_baidu_mapapi_map/ios`)
- flutter_new_badger (from `.symlinks/plugins/flutter_new_badger/ios`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`)
@ -62,6 +76,10 @@ DEPENDENCIES:
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`)
SPEC REPOS:
trunk:
- BaiduMapKit
EXTERNAL SOURCES:
camera_avfoundation:
:path: ".symlinks/plugins/camera_avfoundation/ios"
@ -69,6 +87,10 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/connectivity_plus/ios"
Flutter:
:path: Flutter
flutter_baidu_mapapi_base:
:path: ".symlinks/plugins/flutter_baidu_mapapi_base/ios"
flutter_baidu_mapapi_map:
:path: ".symlinks/plugins/flutter_baidu_mapapi_map/ios"
flutter_new_badger:
:path: ".symlinks/plugins/flutter_new_badger/ios"
fluttertoast:
@ -101,9 +123,12 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/webview_flutter_wkwebview/darwin"
SPEC CHECKSUMS:
BaiduMapKit: 84991811cb07b24c6ead7d59022c13245427782c
camera_avfoundation: be3be85408cd4126f250386828e9b1dfa40ab436
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_baidu_mapapi_base: 24dd82034374c6f52a73e90316834c63ff8d4f64
flutter_baidu_mapapi_map: f799cc1bb3d39196b8d3d59399ca8635e690bd44
flutter_new_badger: 133aaf93e9a5542bf905c8483d8b83c5ef4946ea
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e

View File

@ -200,6 +200,7 @@
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
9D4AB6A98949D5BF69896B41 /* [CP] Embed Pods Frameworks */,
278BCE4BA5CD53A70DAEC00A /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@ -271,6 +272,23 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
278BCE4BA5CD53A70DAEC00A /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;

View File

@ -1,14 +1,77 @@
import Flutter
import UIKit
import Flutter
@main
@objc class AppDelegate: FlutterAppDelegate {
//
static var orientationMask: UIInterfaceOrientationMask = .portrait
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: "app.orientation",
binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler { [weak self] call, result in
guard let self = self else { return }
if call.method == "setOrientation" {
guard let arg = call.arguments as? String else {
result(FlutterError(code: "BAD_ARGS", message: "need 'landscape' | 'portrait'", details: nil))
return
}
//
if arg == "landscape" {
AppDelegate.orientationMask = .landscape
} else if arg == "portrait" {
AppDelegate.orientationMask = .portrait
} else {
result(FlutterError(code: "BAD_ARGS", message: "unknown arg", details: nil))
return
}
//
if #available(iOS 16.0, *) {
// VC supportedInterfaceOrientations
self.window?.rootViewController?.setNeedsUpdateOfSupportedInterfaceOrientations()
if let scene = self.window?.windowScene {
let orientations: UIInterfaceOrientationMask =
(arg == "landscape") ? .landscape : .portrait
do {
try scene.requestGeometryUpdate(.iOS(interfaceOrientations: orientations))
} catch {
result(FlutterError(code: "GEOMETRY_UPDATE_FAILED",
message: error.localizedDescription, details: nil))
return
}
}
} else {
let target: UIInterfaceOrientation =
(arg == "landscape") ? .landscapeLeft : .portrait
UIDevice.current.setValue(target.rawValue, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
}
result(true)
} else {
result(FlutterMethodNotImplemented)
}
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
//
override func application(_ application: UIApplication,
supportedInterfaceOrientationsFor window: UIWindow?)
-> UIInterfaceOrientationMask {
return AppDelegate.orientationMask
}
}

View File

@ -71,12 +71,17 @@
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@ -1,342 +1,71 @@
// baidu_map_webview_debug.dart
import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
/// BaiduMapWebView JS ready /
class BaiduMapWebView extends StatefulWidget {
final String ak; // web (JS API) AK
final double latitude;
final double longitude;
final int zoom; // uniapp scale
final List<Map<String, dynamic>> covers;
final ValueChanged<Map<String, dynamic>>? onMarkerTap;
final Duration readyTimeout;
/// WebView
/// BaiduMapWebView(
/// controller: _controller,
/// isLoading: _isLoading,
/// errorMessage: _errorMessage,
/// onRetry: _initLocation,
/// )
/// ```
class BaiduMapWebView extends StatelessWidget {
final WebViewController? controller;
final bool isLoading;
final String? errorMessage;
final VoidCallback onRetry;
const BaiduMapWebView({
Key? key,
required this.ak,
required this.latitude,
required this.longitude,
this.zoom = 13,
this.covers = const [],
this.onMarkerTap,
this.readyTimeout = const Duration(seconds: 8),
}) : super(key: key);
@override
State<BaiduMapWebView> createState() => _BaiduMapWebViewState();
}
class _BaiduMapWebViewState extends State<BaiduMapWebView> {
late final WebViewController _controller;
bool _pageLoaded = false;
bool _mapReady = false;
String? _lastJsMessage;
Timer? _readyTimer;
bool _showError = false;
String _errorText = '';
String _html(String ak) {
// HTML map setCenter / setMarkersFromFlutter console onerror
return '''
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta charset="utf-8"/>
<style>html,body,#map{height:100%;margin:0;padding:0;background:#f0f0f0}</style>
</head>
<body>
<div id="map"></div>
<script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=$ak"></script>
<script>
// console.logconsole.errorwindow.onerror FlutterBridge
(function(){
function send(kind, msg) {
try { Bridge.postMessage(JSON.stringify({__bridge: true, kind: kind, msg: String(msg)})); } catch(e) {}
}
var _log = console.log;
console.log = function(){
try{ send('log', Array.prototype.slice.call(arguments).join(' ')); }catch(e){}
_log && _log.apply(console, arguments);
};
var _err = console.error;
console.error = function(){
try{ send('error', Array.prototype.slice.call(arguments).join(' ')); }catch(e){}
_err && _err.apply(console, arguments);
};
window.onerror = function(msg, url, line, col, err) {
try{ send('onerror', msg + ' at ' + url + ':' + line + ':' + col + ' -> ' + (err && err.stack? err.stack:'') ); }catch(e){}
};
})();
//
var map;
try {
map = new BMap.Map("map");
map.enableScrollWheelZoom(true);
} catch(e) {
console.error('Map init error', e);
}
function setCenter(lat, lng, zoom) {
try {
if(!map) { console.error('map undefined in setCenter'); return; }
var p = new BMap.Point(lng, lat);
map.centerAndZoom(p, zoom || map.getZoom());
} catch(e) {
console.error('setCenter error', e);
}
}
var markers = [];
function clearMarkers(){
try {
for(var i=0;i<markers.length;i++){
map.removeOverlay(markers[i]);
}
markers = [];
} catch(e) { console.error('clearMarkers error', e); }
}
function setMarkersFromFlutter(coversJson){
try {
if(!map) { console.error('map undefined in setMarkersFromFlutter'); return; }
var arr = JSON.parse(coversJson || '[]');
clearMarkers();
for (var i = 0; i < arr.length; i++) {
var it = arr[i];
if(!it || it.longitude==null || it.latitude==null) continue;
var pt = new BMap.Point(parseFloat(it.longitude), parseFloat(it.latitude));
var marker;
if (it.icon && it.icon.length > 0) {
// 使 base64
var myIcon = new BMap.Icon(it.icon, new BMap.Size(36,36));
marker = new BMap.Marker(pt, {icon: myIcon});
} else {
marker = new BMap.Marker(pt);
}
try {
marker._meta = it.data || it;
} catch(e) { marker._meta = {}; }
(function(m){
m.addEventListener('click', function(){
try { Bridge.postMessage(JSON.stringify(m._meta)); } catch(e) {}
});
})(marker);
markers.push(marker);
map.addOverlay(marker);
}
} catch (e) {
console.error('setMarkersFromFlutter parse error', e);
}
}
// ready
function notifyReady(){
try{ Bridge.postMessage(JSON.stringify({__mapReady:true})); }catch(e){}
}
// map , center ready
(function waitMap(){
try {
if(map && typeof map.centerAndZoom === 'function') {
// initial center (Flutter will call setCenter after load, but still notify)
notifyReady();
} else {
setTimeout(waitMap, 300);
}
} catch(e) {
console.error('waitMap error', e);
}
})();
// API
window.setMarkersFromFlutter = setMarkersFromFlutter;
window.setCenter = setCenter;
</script>
</body>
</html>
''';
}
String _escapeForJs(String s) => s.replaceAll(r'\', r'\\').replaceAll("'", r"\\'").replaceAll('\n', r' ');
@override
void initState() {
super.initState();
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel('Bridge', onMessageReceived: _onJsMessage)
..setNavigationDelegate(NavigationDelegate(
onPageFinished: (url) {
_pageLoaded = true;
_startReadyTimer();
// inject initial center & markers AFTER slight delay to allow JS to define functions
Future.delayed(const Duration(milliseconds: 300), () async {
await _controller.runJavaScript('setCenter(${widget.latitude}, ${widget.longitude}, ${widget.zoom});');
final coversJson = jsonEncode(widget.covers);
await _controller.runJavaScript("setMarkersFromFlutter('${_escapeForJs(coversJson)}');");
});
},
onWebResourceError: (err) {
_reportError('WebResourceError: ${err.description}');
},
))
..loadHtmlString(_html(widget.ak));
}
void _startReadyTimer() {
_readyTimer?.cancel();
_readyTimer = Timer(widget.readyTimeout, () {
if (!mounted) return;
if (!_mapReady) {
setState(() {
_showError = true;
_errorText = '地图初始化超时,可能 AK 无效或网络受限。请检查 AK需为百度 JS API Key与网络。';
});
}
});
}
void _onJsMessage(JavaScriptMessage msg) {
_lastJsMessage = msg.message;
// message
try {
final m = jsonDecode(msg.message);
if (m is Map && m.containsKey('__mapReady') && m['__mapReady'] == true) {
// JS ready
_readyTimer?.cancel();
if (mounted) {
setState(() {
_mapReady = true;
_showError = false;
_errorText = '';
});
}
return;
}
} catch (_) {
// not json meta, maybe marker data or console log
}
// handle console / error wrapper shape: {__bridge:true, kind:..., msg:...}
try {
final decoded = jsonDecode(msg.message);
if (decoded is Map && decoded['__bridge'] == true) {
final kind = decoded['kind'];
final mm = decoded['msg'];
if (kind == 'error' || kind == 'onerror') {
_reportError('JS error: $mm');
} else {
// console log: keep last message (debug only)
debugPrint('JS log: $mm');
}
return;
}
} catch (_) {}
// otherwise treat as marker click payload (likely non-meta JSON)
try {
final payload = jsonDecode(msg.message) as Map<String, dynamic>;
if (widget.onMarkerTap != null) widget.onMarkerTap!(payload);
} catch (e) {
// not JSON? ignore
debugPrint('Unrecognized JS message: ${msg.message}');
}
}
void _reportError(String text) {
debugPrint(text);
if (!mounted) return;
setState(() {
_showError = true;
_errorText = text;
});
}
@override
void didUpdateWidget(covariant BaiduMapWebView oldWidget) {
super.didUpdateWidget(oldWidget);
if (_pageLoaded) {
if (oldWidget.latitude != widget.latitude ||
oldWidget.longitude != widget.longitude ||
oldWidget.zoom != widget.zoom) {
_controller.runJavaScript('setCenter(${widget.latitude}, ${widget.longitude}, ${widget.zoom});');
}
if (!listEquals(oldWidget.covers, widget.covers)) {
final coversJson = jsonEncode(widget.covers);
_controller.runJavaScript("setMarkersFromFlutter('${_escapeForJs(coversJson)}');");
}
}
}
@override
void dispose() {
_readyTimer?.cancel();
super.dispose();
}
super.key,
required this.controller,
required this.isLoading,
required this.errorMessage,
required this.onRetry,
});
@override
Widget build(BuildContext context) {
return Stack(
children: [
WebViewWidget(controller: _controller),
if (!_mapReady && !_showError)
const Center(child: CircularProgressIndicator()),
if (_showError)
Positioned.fill(
child: Container(
color: Colors.white70,
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('地图加载失败', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
Text(_errorText, textAlign: TextAlign.center),
const SizedBox(height: 12),
ElevatedButton(
onPressed: () {
setState(() {
_showError = false;
_mapReady = false;
});
//
_controller.loadHtmlString(_html(widget.ak));
},
child: const Text('重试'),
),
const SizedBox(height: 6),
ElevatedButton(
onPressed: () {
// js message 便
showDialog(
context: context,
builder: (_) => AlertDialog(
title: const Text('JS 消息'),
content: SingleChildScrollView(child: Text(_lastJsMessage ?? '')),
actions: [
TextButton(onPressed: () => Navigator.pop(context), child: const Text('关闭')),
],
),
);
},
child: const Text('查看 JS 日志'),
),
],
),
),
),
if (errorMessage != null) {
return Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(mainAxisSize: MainAxisSize.min, children: [
const Icon(Icons.error_outline, color: Colors.red, size: 50),
const SizedBox(height: 16),
Text(
errorMessage!,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 16),
),
),
],
);
const SizedBox(height: 24),
CustomButton(text: '重试', backgroundColor: Colors.blue, onPressed: onRetry)
]),
),
);
}
if (isLoading) {
return const Center(child: CircularProgressIndicator());
}
// controller
if (controller == null) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.map_outlined, size: 48),
const SizedBox(height: 8),
const Text('地图未初始化'),
const SizedBox(height: 12),
ElevatedButton(onPressed: onRetry, child: const Text('重试初始化')),
],
),
);
}
return WebViewWidget(controller: controller!);
}
}

View File

@ -0,0 +1,203 @@
import 'dart:convert';
import 'package:flutter/material.dart';
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/tools.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:geolocator/geolocator.dart';
class MapPage extends StatefulWidget {
final String gson;
const MapPage({super.key, required this.gson});
@override
State<MapPage> createState() => _MapPageState();
}
class _MapPageState extends State<MapPage> {
late final WebViewController _controller;
bool _isLoading = true;
String? _errorMessage;
double? _longitude;
double? _latitude;
List<dynamic> _gsonList = [];
late Map<String, dynamic> mapData = {};
@override
void initState() {
super.initState();
_initLocation();
}
/// WebView
Future<void> _initLocation() async {
setState(() {
_isLoading = true;
_errorMessage = null;
});
try {
final LocationResult loc = await LocationService.getCurrentLocation(
timeout: const Duration(seconds: 10),
);
// gson
try {
final parsed = jsonDecode(widget.gson);
if (parsed is List) {
_gsonList = parsed;
} else {
_gsonList = [];
}
} catch (e) {
debugPrint('解析 gson 失败: $e');
_gsonList = [];
}
if (!mounted) return;
setState(() {
_longitude = loc.longitudeAsDouble;
_latitude = loc.latitudeAsDouble;
});
// WebViewController
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
// JS 'JS' HTML window.JS.postMessage(...)
..addJavaScriptChannel('JS', onMessageReceived: (dynamic message) {
// message "Undefined class"
String payload;
try {
payload = message.message ?? message.toString();
} catch (e) {
payload = message.toString();
}
_onJsMessage(payload);
})
// 'Flutter'
..addJavaScriptChannel('Flutter', onMessageReceived: (dynamic message) {
String payload;
try {
payload = message.message ?? message.toString();
} catch (e) {
payload = message.toString();
}
_onJsMessage(payload);
})
..setNavigationDelegate(
NavigationDelegate(
onPageFinished: (String url) async {
debugPrint('网页加载完成: $url');
await _injectLocationParams();
},
onWebResourceError: (err) {
debugPrint('Web resource error: ${err.description}');
},
),
);
// assets HTML
// await _controller.loadFlutterAsset('assets/map/test_baidu_map.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(...)
Future<void> _injectLocationParams() async {
if (_longitude == null || _latitude == null) {
debugPrint('位置尚未准备好,跳过注入');
return;
}
final params = {
'longitude': _longitude,
'latitude': _latitude,
'GSON': _gsonList,
't': DateTime.now().millisecondsSinceEpoch,
};
final jsonParams = jsonEncode(params);
try {
await _controller.runJavaScript('''
(function(){
try {
if (typeof window.initWithData === 'function') {
window.initWithData($jsonParams);
} else if (typeof window.initMap === 'function') {
window.initMap($jsonParams);
} else {
console.error('initWithData / initMap function not found');
}
} catch(e) {
console.error('call initWithData error', e);
}
})();
''');
debugPrint('已注入地图初始化参数');
} catch (e) {
debugPrint('注入位置参数失败: $e');
}
}
/// Web JSON
void _onJsMessage(String message) {
debugPrint('收到来自 Web 的消息: $message');
if (message.isEmpty) return;
try {
Map<String,dynamic> data = jsonDecode(message);
if (FormUtils.hasValue(data, 'ok') && data['ok'] == true) {
}else{
if (FormUtils.hasValue(data, 'type') && data['type'] == 'converted') {
setState(() {
mapData = data;
});
}else{
ToastUtil.showNormal(context, '当前选择点位不在区域中');
setState(() {
mapData = {};
});
}
}
} catch (_) {
setState(() {
mapData = {};
});
ToastUtil.showNormal(context, '当前选择点位不在区域中');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '地图选择', actions: [
if (mapData.isNotEmpty)
TextButton(onPressed: (){
Navigator.of(context).pop((mapData));
}, child: Text('确定', style: TextStyle(color: Colors.white, fontSize: 17),))
],),
body: SafeArea(
child: BaiduMapWebView(
controller: _isLoading || _errorMessage != null ? null : _controller,
isLoading: _isLoading,
errorMessage: _errorMessage,
onRetry: _initLocation,
),),
);
}
}

View File

@ -319,7 +319,7 @@ class ListItemFactory {
Text(yesLabel),
],
),
const SizedBox(width: 16),
const SizedBox(width: 5),
Row(
children: [
Radio<bool>(

View File

@ -14,6 +14,9 @@ class CustomAlertDialog extends StatefulWidget {
final ValueChanged<String>? onInputConfirm; //
final DialogMode mode; //
/// force true
final bool force;
const CustomAlertDialog({
Key? key,
required this.title,
@ -25,6 +28,7 @@ class CustomAlertDialog extends StatefulWidget {
this.onConfirm,
this.onInputConfirm,
this.mode = DialogMode.text,
this.force = false,
}) : super(key: key);
@override
@ -42,11 +46,12 @@ class CustomAlertDialog extends StatefulWidget {
String confirmText = '确定',
bool barrierDismissible = true,
final VoidCallback? onConfirm,
bool force = false, //
}) async {
final result = await showDialog<bool>(
context: context,
barrierDismissible: barrierDismissible,
// force
barrierDismissible: force ? false : barrierDismissible,
builder: (_) {
return CustomAlertDialog(
title: title,
@ -55,6 +60,7 @@ class CustomAlertDialog extends StatefulWidget {
confirmText: confirmText,
mode: DialogMode.text,
onConfirm: onConfirm,
force: force,
);
},
);
@ -69,11 +75,11 @@ class CustomAlertDialog extends StatefulWidget {
String confirmText = '确定',
bool barrierDismissible = true,
final VoidCallback? onConfirm,
bool force = false, //
}) async {
await showDialog<void>(
context: context,
barrierDismissible: barrierDismissible,
barrierDismissible: force ? false : barrierDismissible,
builder: (_) {
return CustomAlertDialog(
title: title,
@ -82,7 +88,7 @@ class CustomAlertDialog extends StatefulWidget {
confirmText: confirmText,
mode: DialogMode.text,
onConfirm: onConfirm,
force: force,
);
},
);
@ -96,10 +102,11 @@ class CustomAlertDialog extends StatefulWidget {
String cancelText = '取消',
String confirmText = '确定',
bool barrierDismissible = true,
bool force = false, //
}) async {
final result = await showDialog<String?>(
context: context,
barrierDismissible: barrierDismissible,
barrierDismissible: force ? false : barrierDismissible,
builder: (_) {
return CustomAlertDialog(
title: title,
@ -107,6 +114,7 @@ class CustomAlertDialog extends StatefulWidget {
cancelText: cancelText,
confirmText: confirmText,
mode: DialogMode.input,
force: force,
);
},
);
@ -130,69 +138,83 @@ class _CustomAlertDialogState extends State<CustomAlertDialog> {
super.dispose();
}
bool get hasCancel => widget.cancelText.trim().isNotEmpty;
/// force true
bool get hasCancel => !widget.force && widget.cancelText.trim().isNotEmpty;
/// dialog mount
void _closeDialog([dynamic result]) {
if (!mounted) return;
Navigator.of(context).pop(result);
}
@override
Widget build(BuildContext context) {
return Dialog(
backgroundColor: Colors.transparent,
child: Container(
constraints: const BoxConstraints(minWidth: 280),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Text(
widget.title,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
const SizedBox(height: 16),
// mode
if (widget.mode == DialogMode.text)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Text(
widget.content,
style: const TextStyle(fontSize: 16, color: Colors.black54),
textAlign: TextAlign.center,
),
)
else
// 使 WillPopScope force true
return WillPopScope(
onWillPop: () async {
// falsetrue
return !widget.force;
},
child: Dialog(
backgroundColor: Colors.transparent,
child: Container(
constraints: const BoxConstraints(minWidth: 280),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: TextField(
controller: _controller,
autofocus: true,
decoration: InputDecoration(
hintText: widget.hintText,
border: const OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 1),
borderRadius: BorderRadius.circular(4),
),
isDense: true,
contentPadding: const EdgeInsets.symmetric(
vertical: 10,
horizontal: 10,
child: Text(
widget.title,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
const SizedBox(height: 16),
// mode
if (widget.mode == DialogMode.text)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Text(
widget.content,
style: const TextStyle(fontSize: 16, color: Colors.black54),
textAlign: TextAlign.center,
),
)
else
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: TextField(
controller: _controller,
autofocus: true,
decoration: InputDecoration(
hintText: widget.hintText,
border: const OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 1),
borderRadius: BorderRadius.circular(4),
),
isDense: true,
contentPadding: const EdgeInsets.symmetric(
vertical: 10,
horizontal: 10,
),
),
),
),
),
const SizedBox(height: 20),
const Divider(height: 1),
const SizedBox(height: 20),
const Divider(height: 1),
hasCancel ? _buildDoubleButtons(context) : _buildSingleButton(context),
],
hasCancel ? _buildDoubleButtons(context) : _buildSingleButton(context),
],
),
),
),
);
@ -209,7 +231,7 @@ class _CustomAlertDialogState extends State<CustomAlertDialog> {
final ret = widget.mode == DialogMode.text ? false : null;
//
widget.onCancel?.call();
Navigator.of(context).pop(ret);
_closeDialog(ret);
},
child: Container(
padding: const EdgeInsets.symmetric(vertical: 12),
@ -234,11 +256,11 @@ class _CustomAlertDialogState extends State<CustomAlertDialog> {
onTap: () {
if (widget.mode == DialogMode.text) {
widget.onConfirm?.call();
Navigator.of(context).pop(true);
_closeDialog(true);
} else {
final value = _controller.text.trim();
widget.onInputConfirm?.call(value);
Navigator.of(context).pop(value);
_closeDialog(value);
}
},
child: Container(
@ -264,11 +286,11 @@ class _CustomAlertDialogState extends State<CustomAlertDialog> {
onTap: () {
if (widget.mode == DialogMode.text) {
widget.onConfirm?.call();
Navigator.of(context).pop(true);
_closeDialog(true);
} else {
final value = _controller.text.trim();
widget.onInputConfirm?.call(value);
Navigator.of(context).pop(value);
_closeDialog(value);
}
},
child: Container(

View File

@ -79,6 +79,7 @@ class _DepartmentPickerState extends State<DepartmentPicker> {
final String nodes = result['zTreeNodes'] as String;
SessionService.instance.departmentJsonStr = nodes;
raw = json.decode(nodes) as List<dynamic>;
}
setState(() {
original = raw.map((e) => Category.fromJson(e as Map<String, dynamic>)).toList();

View File

@ -5,12 +5,17 @@ import 'package:flutter/material.dart';
/// DateTime? picked = await BottomDateTimePicker.showDate(
/// context,
/// allowFuture: true, //
/// minTimeStr: '2025-08-20 08:30', //
/// );
/// if (picked != null) {
/// print('用户选择的时间:$picked');
/// }
class BottomDateTimePicker {
static Future<DateTime?> showDate(BuildContext context, {bool allowFuture = false}) {
static Future<DateTime?> showDate(
BuildContext context, {
bool allowFuture = false,
String? minTimeStr, // 'yyyy-MM-dd HH:mm'
}) {
return showModalBottomSheet<DateTime>(
context: context,
backgroundColor: Colors.white,
@ -18,21 +23,31 @@ class BottomDateTimePicker {
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
),
builder: (_) => _InlineDateTimePickerContent(allowFuture: allowFuture),
builder: (_) => _InlineDateTimePickerContent(
allowFuture: allowFuture,
minTimeStr: minTimeStr,
),
);
}
}
class _InlineDateTimePickerContent extends StatefulWidget {
final bool allowFuture; //
final String? minTimeStr; // 'yyyy-MM-dd HH:mm'
const _InlineDateTimePickerContent({Key? key, this.allowFuture = false}) : super(key: key);
const _InlineDateTimePickerContent({
Key? key,
this.allowFuture = false,
this.minTimeStr,
}) : super(key: key);
@override
State<_InlineDateTimePickerContent> createState() => _InlineDateTimePickerContentState();
State<_InlineDateTimePickerContent> createState() =>
_InlineDateTimePickerContentState();
}
class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerContent> {
class _InlineDateTimePickerContentState
extends State<_InlineDateTimePickerContent> {
//
final List<int> years = List.generate(101, (i) => 1970 + i);
final List<int> months = List.generate(12, (i) => i + 1);
@ -56,24 +71,43 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
late int selectedHour;
late int selectedMinute;
DateTime? _minTime; //
@override
void initState() {
super.initState();
// minTimeStr
_minTime = _parseMinTime(widget.minTimeStr);
// DateTime.now() _minTime
final now = DateTime.now();
selectedYear = now.year;
selectedMonth = now.month;
selectedDay = now.day;
selectedHour = now.hour;
selectedMinute = now.minute;
DateTime initial = now;
if (_minTime != null && _minTime!.isAfter(initial)) {
initial = _minTime!;
}
selectedYear = initial.year;
selectedMonth = initial.month;
selectedDay = initial.day;
selectedHour = initial.hour;
selectedMinute = initial.minute;
//
days = _getDaysInMonth(selectedYear, selectedMonth);
yearCtrl = FixedExtentScrollController(initialItem: years.indexOf(selectedYear));
monthCtrl = FixedExtentScrollController(initialItem: selectedMonth - 1);
dayCtrl = FixedExtentScrollController(initialItem: selectedDay - 1);
hourCtrl = FixedExtentScrollController(initialItem: selectedHour);
minuteCtrl = FixedExtentScrollController(initialItem: selectedMinute);
// controllers
yearCtrl = FixedExtentScrollController(
initialItem: years.indexOf(selectedYear).clamp(0, years.length - 1));
monthCtrl = FixedExtentScrollController(initialItem: (selectedMonth - 1).clamp(0, months.length - 1));
dayCtrl = FixedExtentScrollController(initialItem: (selectedDay - 1).clamp(0, days.length - 1));
hourCtrl = FixedExtentScrollController(initialItem: selectedHour.clamp(0, hours.length - 1));
minuteCtrl = FixedExtentScrollController(initialItem: selectedMinute.clamp(0, minutes.length - 1));
// minTime
WidgetsBinding.instance.addPostFrameCallback((_) {
_enforceConstraintsAndUpdateControllers();
});
}
//
@ -82,8 +116,31 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
return List.generate(lastDay, (i) => i + 1);
}
// 'yyyy-MM-dd HH:mm' DateTime null
DateTime? _parseMinTime(String? s) {
if (s == null || s.trim().isEmpty) return null;
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)
? parts[1].split(':').map((e) => int.parse(e)).toList()
: [0, 0];
final year = dateParts[0];
final month = dateParts[1];
final day = dateParts[2];
final hour = (timeParts.isNotEmpty) ? timeParts[0] : 0;
final minute = (timeParts.length > 1) ? timeParts[1] : 0;
return DateTime(year, month, day, hour, minute);
} catch (e) {
//
debugPrint('parseMinTime failed for "$s": $e');
return null;
}
}
//
void _updateDays() {
void _updateDays({bool jumpDay = true}) {
final newDays = _getDaysInMonth(selectedYear, selectedMonth);
final isDayValid = selectedDay <= newDays.length;
@ -91,35 +148,56 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
days = newDays;
if (!isDayValid) {
selectedDay = newDays.last;
dayCtrl.jumpToItem(selectedDay - 1);
if (jumpDay) dayCtrl.jumpToItem(selectedDay - 1);
}
});
}
//
void _checkAndClampToNow() {
if (widget.allowFuture) return; //
//
// 1) _minTime _minTime
// 2) _minTime allowFuture now
// _minTime allowFuture _minTime _minTime
void _enforceConstraintsAndUpdateControllers() {
final picked = DateTime(selectedYear, selectedMonth, selectedDay, selectedHour, selectedMinute);
final now = DateTime.now();
if (picked.isAfter(now)) {
//
selectedYear = now.year;
selectedMonth = now.month;
selectedDay = now.day;
selectedHour = now.hour;
selectedMinute = now.minute;
// 1)
if (_minTime != null && picked.isBefore(_minTime!)) {
final m = _minTime!;
selectedYear = m.year;
selectedMonth = m.month;
selectedDay = m.day;
selectedHour = m.hour;
selectedMinute = m.minute;
//
//
_updateDays(jumpDay: false);
yearCtrl.jumpToItem(years.indexOf(selectedYear));
monthCtrl.jumpToItem(selectedMonth - 1);
dayCtrl.jumpToItem(selectedDay - 1);
hourCtrl.jumpToItem(selectedHour);
minuteCtrl.jumpToItem(selectedMinute);
return;
}
//
_updateDays();
// 2) allowFuture == false minTime minTime <= now
if (!widget.allowFuture) {
final now = DateTime.now();
// minTime nowminTime
if (picked.isAfter(now)) {
selectedYear = now.year;
selectedMonth = now.month;
selectedDay = now.day;
selectedHour = now.hour;
selectedMinute = now.minute;
_updateDays(jumpDay: false);
yearCtrl.jumpToItem(years.indexOf(selectedYear));
monthCtrl.jumpToItem(selectedMonth - 1);
dayCtrl.jumpToItem(selectedDay - 1);
hourCtrl.jumpToItem(selectedHour);
minuteCtrl.jumpToItem(selectedMinute);
return;
}
}
}
@ -136,7 +214,7 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
@override
Widget build(BuildContext context) {
return SizedBox(
height: 300,
height: 330,
child: Column(
children: [
//
@ -178,8 +256,8 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
onSelected: (idx) {
setState(() {
selectedYear = years[idx];
_updateDays(); //
_checkAndClampToNow();
_updateDays();
_enforceConstraintsAndUpdateControllers();
});
},
),
@ -191,8 +269,8 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
onSelected: (idx) {
setState(() {
selectedMonth = months[idx];
_updateDays(); //
_checkAndClampToNow();
_updateDays();
_enforceConstraintsAndUpdateControllers();
});
},
),
@ -203,8 +281,10 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
items: days.map((e) => e.toString().padLeft(2, '0')).toList(),
onSelected: (idx) {
setState(() {
selectedDay = days[idx];
_checkAndClampToNow();
// idx days
final safeIdx = idx.clamp(0, days.length - 1);
selectedDay = days[safeIdx];
_enforceConstraintsAndUpdateControllers();
});
},
),
@ -216,7 +296,7 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
onSelected: (idx) {
setState(() {
selectedHour = hours[idx];
_checkAndClampToNow();
_enforceConstraintsAndUpdateControllers();
});
},
),
@ -228,7 +308,7 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
onSelected: (idx) {
setState(() {
selectedMinute = minutes[idx];
_checkAndClampToNow();
_enforceConstraintsAndUpdateControllers();
});
},
),
@ -257,4 +337,4 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
),
);
}
}
}

View File

@ -0,0 +1,348 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
import 'package:qhd_prevention/pages/main_tab.dart';
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/http/ApiService.dart';
import 'package:qhd_prevention/tools/tools.dart';
class PromisePage extends StatefulWidget {
const PromisePage({super.key});
@override
State<PromisePage> createState() => _PromisePageState();
}
class _PromisePageState extends State<PromisePage> {
bool _loading = true;
Map<String, dynamic> info = {};
String? baseImgPath;
@override
void initState() {
super.initState();
_loadData();
}
Future<void> _loadData() async {
setState(() {
_loading = true;
});
try {
final Map<String, dynamic> payload =
await ApiService.safeCorppromiseDetail();
final coll = (payload['COLLATERAL'] as List?) ?? [];
final DETAIL =
coll.map((e) {
return {
'value': e?['COLLATERAL']?.toString() ?? '',
'id': e?['PROMISEDETAIL_ID']?.toString() ?? '',
};
}).toList();
final Map<String, dynamic> resolved = {};
if (payload['TEXT'] is Map) {
resolved.addAll(payload['TEXT'] as Map<String, dynamic>);
} else {
resolved['TEXT'] = payload['TEXT']?.toString() ?? '';
}
resolved['DETAIL'] = DETAIL;
resolved['SIGNTIME'] =
DateTime.now().millisecondsSinceEpoch.toString();
resolved['COVERPEOPLE'] =
(payload['COVERPEOPLE'] is List && payload['COVERPEOPLE'].isNotEmpty)
? payload['COVERPEOPLE'][0]['USERNAME']?.toString() ?? ''
: '';
//
if (payload is Map<String, dynamic>) {
payload.forEach((k, v) {
if (!resolved.containsKey(k)) resolved[k] = v;
});
}
resolved['PROMISEPEOPLE_ID'] = payload['PROMISEPEOPLE_ID'] ?? '';
setState(() {
info = resolved;
_loading = false;
});
} catch (e, st) {
debugPrint('safeCorppromiseDetail error: $e\n$st');
setState(() {
_loading = false;
});
ToastUtil.showNormal(context, '加载失败,请稍后重试');
}
}
String _formatDateShort(String? s) {
if (s == null) return '';
if (s.length >= 10) return s.substring(0, 10);
return s;
}
// String
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final String path = await Navigator.push(
context,
MaterialPageRoute(builder: (c) => MineSignPage()),
);
if (path != null) {
setState(() {
info['FILEPATH'] = path;
});
FocusHelper.clearFocus(context);
}
}
// / API ApiService.editPeopleII
Future<void> submitSignedPromise() async {
LoadingDialogHelper.show();
final filePath = (info['FILEPATH'] ?? '').toString();
if (filePath.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
final result = await ApiService.submitCorppromiseSign(filePath,info);
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '提交成功');
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => const MainPage()),
);
}
}
Widget _buildTitle() {
final type = (info['TYPE'] ?? '').toString();
final title = type == '0' ? '安全生产承诺书' : '安全生产责任状';
return Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: Text(
title,
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
);
}
Widget _buildHeaderName() {
final type = (info['TYPE'] ?? '').toString();
if (type == '0') {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
'${info['COVERPEOPLE'] ?? ''}',
style: const TextStyle(fontSize: 16),
),
);
}
return const SizedBox.shrink();
}
Widget _buildParagraph(String text) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 8.0),
child: RichText(
textAlign: TextAlign.justify,
text: TextSpan(
style: const TextStyle(
height: 1.6,
letterSpacing: 0.5,
color: Colors.black,
),
children: [
const WidgetSpan(
child: SizedBox(width: 28), // 2
),
TextSpan(text: text),
],
),
),
);
}
Widget _buildCollateralList() {
final detail = (info['DETAIL'] as List?) ?? [];
if (detail.isEmpty) return const SizedBox.shrink();
return Padding(
padding: const EdgeInsets.only(left: 0, right: 8.0, top: 6.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children:
detail.map((e) {
return _buildParagraph(e['value']?.toString() ?? '');
}).toList(),
),
);
}
Widget _buildFooter() {
final type = (info['TYPE'] ?? '').toString();
final signImagePath = (info['FILEPATH'] ?? '').toString();
final signTime = (info['SIGNTIME'] ?? '').toString();
final creatTime = (info['CREATTIME'] ?? '').toString();
Widget signPreview;
if (signImagePath.isNotEmpty && signImagePath.startsWith('http')) {
signPreview = Image.network(
(baseImgPath ?? '') + signImagePath,
width: 100,
height: 50,
fit: BoxFit.cover,
);
} else if (signImagePath.isNotEmpty && File(signImagePath).existsSync()) {
signPreview = Image.file(
File(signImagePath),
width: 100,
height: 50,
fit: BoxFit.cover,
);
} else {
signPreview = const SizedBox.shrink();
}
return Padding(
padding: const EdgeInsets.only(
top: 12.0,
left: 8.0,
right: 8.0,
bottom: 20.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (type == '0')
const Align(
alignment: Alignment.centerRight,
child: Text('承诺单位(盖章)'),
),
if (type == '1')
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text('发状人:${info['COVERPEOPLE'] ?? ''}'),
const SizedBox(height: 6),
Text(creatTime.isNotEmpty ? _formatDateShort(creatTime) : ''),
],
),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(type == '0' ? '主要负责人签字:' : '受状人:'),
const SizedBox(height: 8),
GestureDetector(
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: info['FILEPATH'] ?? ''),
context,
);
},
child: signPreview,
),
const SizedBox(height: 8),
CustomButton(
text:
(info['FILEPATH'] ?? '').toString().isNotEmpty
? '重签'
: '手写签字',
backgroundColor: Colors.blue,
padding: EdgeInsets.symmetric(
vertical: 0,
horizontal: 20,
),
height: 35,
onPressed: _sign,
),
],
),
),
],
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const SizedBox(),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [Text(signTime)],
),
],
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const MyAppbar(title: '安全承诺', isBack: false),
body:
_loading
? const Center(child: CircularProgressIndicator())
: SingleChildScrollView(
child: Container(
color: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 5,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [_buildTitle()],
),
_buildHeaderName(),
_buildParagraph(info['TEXT']?.toString() ?? ''),
_buildCollateralList(),
if ((info['TYPE'] ?? '').toString() == '0') ...[
_buildParagraph(
'若违反上述承诺和未履行安全生产职责,或发生责任事故的,接受政府或公司事故调查组做出的处罚决定。',
),
_buildParagraph(
'承诺期限自${_formatDateShort(info['PROMISE_TERM_START']?.toString())}${_formatDateShort(info['PROMISE_TERM_END']?.toString())}',
),
] else ...[
_buildParagraph(
'若未履行安全生产职责,或发生生产安全事故的,接受公司或政府事故调查组做出的处罚。',
),
_buildParagraph(
'责任期限自${_formatDateShort(info['PROMISE_TERM_START']?.toString())}${_formatDateShort(info['PROMISE_TERM_END']?.toString())}',
),
],
const SizedBox(height: 8),
_buildFooter(),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: CustomButton(
text: '提 交',
backgroundColor: Colors.blue,
onPressed: submitSignedPromise,
),
),
],
),
),
),
);
}
}

View File

@ -194,6 +194,51 @@ U6Hzm1ninpWeE+awIDAQAB
data: {},
);
}
///
static Future<Map<String, dynamic>> checkSafeCorppromise() async {
return HttpManager().request(
basePath,
'/app/corppromise/ISSIGN_II',
method: Method.post,
data: {
'USER_ID': SessionService.instance.loginUserId,
},
);
}
///
static Future<Map<String, dynamic>> safeCorppromiseDetail() async {
return HttpManager().request(
basePath,
'/app/corppromise/promise_II',
method: Method.post,
data: {
'USER_ID': SessionService.instance.loginUserId,
},
);
}
// ///
static Future<Map<String, dynamic>> submitCorppromiseSign(String imagePath, Map data) async {
final file = File(imagePath);
if (!await file.exists()) {
throw ApiException('file_not_found', '图片不存在:$imagePath');
}
final fileName = file.path.split(Platform.pathSeparator).last;
return HttpManager().uploadFaceImage(
baseUrl: basePath,
path: '/app/corppromise/editpeople_II',
fromData: {
...data,
'CORPINFO_ID': SessionService.instance.corpinfoId,
'FFILE': await MultipartFile.fromFile(
file.path,
filename: fileName
),
}
);
}
///
static Future<Map<String, dynamic>> getRecordMapInfo(String CHECKRECORD_ID) {
return HttpManager().request(
@ -558,6 +603,21 @@ U6Hzm1ninpWeE+awIDAQAB
}
///TODO --------------------------------- ---------------------------------
///
static Future<Map<String, dynamic>> checkSpecialWorkIsInPls(String ELECTRONIC_FENCE_AREA_ID, String LONGITUDE, String LATITUDE) {
return HttpManager().request(
basePath,
'/app/eightwork/isInPls',
method: Method.post,
data: {
"CORPINFO_ID":SessionService.instance.corpinfoId,
"USER_ID":SessionService.instance.loginUserId,
"ELECTRONIC_FENCE_AREA_ID":ELECTRONIC_FENCE_AREA_ID,
"LONGITUDE" :LONGITUDE,
"LATITUDE" : LATITUDE,
},
);
}
///
static Future<Map<String, dynamic>> specialCheckWork() {
return HttpManager().request(
@ -783,7 +843,39 @@ U6Hzm1ninpWeE+awIDAQAB
},
);
}
///
static Future<Map<String, dynamic>> getVideomanagerList() {
return HttpManager().request(
basePath,
'/app/videomanager/listAll',
method: Method.post,
data: {
"CORPINFO_ID":SessionService.instance.corpinfoId,
},
);
}
///
static Future<Map<String, dynamic>> getUnitListAll() {
return HttpManager().request(
basePath,
'/app/units/listAll',
method: Method.post,
data: {
"CORPINFO_ID":SessionService.instance.corpinfoId,
},
);
}
///
static Future<Map<String, dynamic>> getWorkAreaList() {
return HttpManager().request(
basePath,
'/app/electronicFence/listTree',
method: Method.post,
data: {
"CORPINFO_ID":SessionService.instance.corpinfoId,
},
);
}
///
static Future<Map<String, dynamic>> saveGasTest(String workType,

View File

@ -1,6 +1,7 @@
import 'dart:io';
import 'dart:ui';
import 'package:dio/dio.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
///
class ApiException implements Exception {
@ -82,9 +83,12 @@ class HttpManager {
try {
switch (method) {
case Method.get:
final queryParameters = <String, dynamic>{};
if (params != null) queryParameters.addAll(params);
if (data != null) queryParameters.addAll(data);
resp = await _dio.get(
url,
queryParameters: params,
queryParameters: queryParameters,
cancelToken: cancelToken,
options: options,
);
@ -128,12 +132,12 @@ class HttpManager {
final json = resp.data is Map<String, dynamic>
? resp.data as Map<String, dynamic>
: <String, dynamic>{};
final result = json['result'] as String?;
final msg = json['msg'] as String? ?? json['message'] as String? ?? '';
if (result != 'success') {
// success
throw ApiException(result ?? 'unknown', msg);
}
// final result = json['result'] as String?;
// final msg = json['msg'] as String? ?? json['message'] as String? ?? '';
// if (result != 'success') {
// // success
// throw ApiException(result ?? 'unknown', msg);
// }
return json;
}
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:qhd_prevention/pages/badge_manager.dart';
import 'package:qhd_prevention/tools/auth_service.dart';
import 'package:qhd_prevention/services/auth_service.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:shared_preferences/shared_preferences.dart';
import './pages/login_page.dart';
import './pages/main_tab.dart';
@ -60,7 +61,6 @@ void main() async {
GlobalMessage.showError('会话已过期,请重新登录');
});
};
//
final prefs = await SharedPreferences.getInstance();
final savedLogin = prefs.getBool('isLoggedIn') ?? false;

View File

@ -14,7 +14,9 @@ import 'package:qhd_prevention/pages/app/danger_wait_list_page.dart';
import 'package:qhd_prevention/pages/app/detail_images_page.dart';
import 'package:qhd_prevention/pages/app/hidden_record_detail_page.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/services/location_service.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:webview_flutter/webview_flutter.dart';
class CheckRecordDetailPage extends StatefulWidget {
const CheckRecordDetailPage(this.id, this.type, {super.key});
@ -31,6 +33,7 @@ class _CheckRecordDetailPageState extends State<CheckRecordDetailPage> {
List<Map<String, dynamic>> covers = [];
double centerLat = 39.8883;
double centerLng = 119.519;
WebViewController? _controller;
Map<String, dynamic> pd = {
"LIST_NAME": "",
@ -58,8 +61,13 @@ class _CheckRecordDetailPageState extends State<CheckRecordDetailPage> {
super.initState();
// UI 使 setState
_fetchAll();
_initLocation();
}
@override
void dispose() {
_controller = null;
super.dispose();
}
Future<void> _fetchAll() async {
//
await Future.wait([
@ -73,12 +81,6 @@ class _CheckRecordDetailPageState extends State<CheckRecordDetailPage> {
setState(() => _loadingMap = true);
try {
final resData = await ApiService.getRecordMapInfo(widget.id);
if (resData == null) {
//
setState(() => _loadingMap = false);
return;
}
final built = buildCoversFromRes(resData);
double lat = centerLat;
double lng = centerLng;
@ -367,6 +369,71 @@ class _CheckRecordDetailPageState extends State<CheckRecordDetailPage> {
),
);
}
/// WebView
Future<void> _initLocation() async {
//
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel('JS', onMessageReceived: (JavaScriptMessage message) {
debugPrint('JS LOG: ${message.message}');
})
..setNavigationDelegate(
NavigationDelegate(
onPageFinished: (String url) async {
debugPrint('网页加载完成: $url');
await _injectLocationParams();
},
onWebResourceError: (err) {
debugPrint('Web resource error: ${err.description}');
},
),
);
// loadRequest
try {
await _controller!.loadRequest(Uri.parse('http://47.92.102.56:7811/file/fluteightmap/index.html'));
} catch (e, st) {
debugPrint('loadRequest 错误: $e\n$st');
}
}
Future<void> _injectLocationParams() async {
if (_controller == null) {
debugPrint('_injectLocationParams: controller 为空,跳过注入');
return;
}
final params = {
'longitude': centerLng,
'latitude': centerLat,
'GSON': [],
't': DateTime.now().millisecondsSinceEpoch,
};
final jsonParams = jsonEncode(params);
try {
await _controller!.runJavaScript('''
(function(){
try {
if (typeof window.initWithData === 'function') {
window.initWithData($jsonParams);
} else if (typeof window.initMap === 'function') {
window.initMap($jsonParams);
} else {
console.error('initWithData / initMap function not found');
}
} catch(e) {
console.error('call initWithData error', e);
}
})();
''');
debugPrint('已注入地图初始化参数');
} catch (e) {
debugPrint('注入位置参数失败: $e');
}
}
Widget _buildTableHeaderCell(String text) {
return Padding(padding: EdgeInsets.all(8), child: Center(child: Text(text, style: TextStyle(fontWeight: FontWeight.bold))));
@ -382,24 +449,11 @@ class _CheckRecordDetailPageState extends State<CheckRecordDetailPage> {
child: _loadingMap
? Center(child: CircularProgressIndicator())
: BaiduMapWebView(
ak: Platform.isIOS ? 'g3lZyqt0KkFnZGUsjIVO7U6lTCfpjSCt' : '43G1sKuHV6oRTrdR9VTIGPF9soej7V5a',
latitude: centerLat,
longitude: centerLng,
zoom: 13,
covers: covers,
onMarkerTap: (data) {
debugPrint('marker click: $data');
// data item id
final type = data['type'] ?? '';
if (type == 'varList' && data['item'] != null) {
//
final item = data['item'];
if (item is Map && item['HIDDEN_ID'] != null) {
_goToDetail(item['HIDDEN_ID'].toString());
}
}
},
),
controller: _controller,
isLoading: _loadingMap,
errorMessage: null,
onRetry: _initLocation,
)
),
);
}

View File

@ -476,10 +476,13 @@ class _CheckingInformationOnePageState extends State<CheckingInformationOnePage>
height: 30,
child: ElevatedButton(
onPressed: () async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
//
setState(() {
imagePath = path ?? '';

View File

@ -272,14 +272,15 @@ class _SafecheckSignDetailState extends State<SafecheckSignDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages = [];
signTimes = [];
signImages.add(path);

View File

@ -258,14 +258,15 @@ class _CheckPersonDetailState extends State<CheckPersonDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages = [];
signTimes = [];
signImages.add(path);

View File

@ -59,14 +59,15 @@ class _SafecheckDefendSetPageState extends State<SafecheckDefendSetPage> {
}
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages = [];
signTimes = [];
signImages.add(path);

View File

@ -560,14 +560,15 @@ class _SafecheckStartDetailState extends State<SafecheckStartDetail> {
}
}
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);

View File

@ -447,6 +447,7 @@ class _CompanySafetyCommitmentApplyState extends State<CompanySafetyCommitmentAp
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final String path = await Navigator.push(
context,
MaterialPageRoute(builder: (c) => MineSignPage()),

View File

@ -36,19 +36,19 @@ class _SafetyCommitmentPageState extends State<SafetyCommitmentPage> {
),
const Divider(),
// Padding(padding: EdgeInsets.only(top: 10),
// child:ItemListWidget.selectableLineTitleTextRightButton(
// label: '其他行业安全承诺:',
// isEditable: true,
// isRequired:false,
// onTap: () {
// pushPage(SafetyCommitmentOtherListPage(), context);
//
// },
// text: ' ',
// ),
// ),
// const Divider(),
Padding(padding: EdgeInsets.only(top: 10),
child:ItemListWidget.selectableLineTitleTextRightButton(
label: '其他行业安全承诺:',
isEditable: true,
isRequired:false,
onTap: () {
pushPage(SafetyCommitmentOtherListPage(), context);
},
text: ' ',
),
),
const Divider(),
],
),
);

View File

@ -817,6 +817,7 @@ class _TeamSafetyCommitmentApplyState extends State<TeamSafetyCommitmentApply> {
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final String path = await Navigator.push(
context,
MaterialPageRoute(builder: (c) => MineSignPage()),

View File

@ -780,6 +780,7 @@ class _WorkShopSafetyCommitmentApplyState extends State<WorkShopSafetyCommitment
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final String path = await Navigator.push(
context,
MaterialPageRoute(builder: (c) => MineSignPage()),

View File

@ -296,6 +296,7 @@ class _SafetyMeetingDetailPageState extends State<SafetyMeetingDetailPage> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),

View File

@ -3,8 +3,10 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
import 'package:qhd_prevention/customWidget/promise/promise_page.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/tools/auth_service.dart';
import 'package:qhd_prevention/services/auth_service.dart';
import 'package:qhd_prevention/tools/update/update_dialogs.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/pages/KeyProjects/keyProjects_tab_list.dart';
@ -188,12 +190,32 @@ class _HomePageState extends State<HomePage> {
context,
title: '更新通知',
content: pd['UPLOAD_CONTENT'] ?? '',
onConfirm: () {
ToastUtil.showNormal(context, '更新去吧!');
onConfirm: () async{
final apkUrl = 'http://192.168.1.191:8888/app-release.apk';
await showUpdateConfirmDialog(context, apkUrl: apkUrl);
},
);
return;
}
final corppromiseData = await ApiService.checkSafeCorppromise();
if (corppromiseData['ISSIGN'] == 1) {
//
CustomAlertDialog.showConfirm(
context,
title: '温馨提示',
content: '有未签署的安全承诺,点击确认前往签署',
force: true,
onConfirm: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => const PromisePage()),
);
},
);
return;
}
await _loadHiddenCache();
// + hiddenList loading
await _fetchData();

View File

@ -142,10 +142,13 @@ class _StudyMyTaskPageState extends State<StudyMyTaskPage> {
}
void _onTapSign(Map item) async {
await NativeOrientation.setLandscape();
final String? imagePath = await Navigator.push<String>(
context,
MaterialPageRoute(builder: (_) => MineSignPage()),
);
await NativeOrientation.setPortrait();
// imagePath
if (imagePath != null && imagePath.isNotEmpty) {

View File

@ -8,6 +8,9 @@ import 'package:qhd_prevention/tools/tools.dart';
class ItemListWidget {
static const Color detailtextColor = Colors.black54;
static const double requiredInset = 0;
static const double horizontal_inset = 12;
static const double vertical_inset = 5;
///
/// - + TextField
@ -28,7 +31,7 @@ class ItemListWidget {
TextInputType keyboardType = TextInputType.text,
}) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
padding: const EdgeInsets.symmetric(vertical: vertical_inset, horizontal: horizontal_inset),
child: Row(
mainAxisAlignment:
isEditable
@ -164,12 +167,12 @@ class ItemListWidget {
VoidCallback? onTapClean, //
bool isRequired = true,
String cleanText = '清除',
double horizontalnum=12,
double horizontalnum= horizontal_inset,
}) {
return InkWell(
onTap: isEditable ? onTap : null,
child: Container(
padding: EdgeInsets.symmetric(vertical: 5, horizontal: horizontalnum),
padding: EdgeInsets.symmetric(vertical: vertical_inset, horizontal: horizontalnum),
child: Row(
children: [
// 1.
@ -214,7 +217,7 @@ class ItemListWidget {
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: fontSize,
color: isEditable ? Colors.black : detailtextColor,
color: isEditable ? (text == '请选择' ? Colors.black87 :Colors.black) : detailtextColor,
),
),
),
@ -250,7 +253,7 @@ class ItemListWidget {
return InkWell(
onTap: isEditable ? onTap : null,
child: Container(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
padding: const EdgeInsets.symmetric(vertical: vertical_inset, horizontal: horizontal_inset),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -334,7 +337,7 @@ class ItemListWidget {
bool isRequired = true,
}) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
padding: EdgeInsets.symmetric(vertical: vertical_inset, horizontal: horizontal_inset),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -415,16 +418,18 @@ class ItemListWidget {
static Widget twoRowButtonTitleText({
required String label, //
required bool isEditable, //
bool isInput = true, //
required String text, //
TextEditingController? controller, //
required VoidCallback? onTap, //
String buttonText = '选择其他',
required String hintText,
double fontSize = 15, //
double row2Height = 80, //
bool isRequired = true,
}) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
padding: const EdgeInsets.symmetric(vertical: vertical_inset, horizontal: horizontal_inset),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -455,12 +460,13 @@ class ItemListWidget {
const SizedBox(width: 8),
if (isEditable)
CustomButton(
text: "选择其他",
text: buttonText,
height: 30,
padding: const EdgeInsets.symmetric(
vertical: 2,
horizontal: 5,
horizontal: 10,
),
textStyle: TextStyle(color: Colors.white, fontSize: 11, fontWeight: FontWeight.bold),
backgroundColor: Colors.green,
onPressed: onTap,
),
@ -473,7 +479,7 @@ class ItemListWidget {
height: row2Height,
padding: const EdgeInsets.symmetric(vertical: 8),
child:
isEditable
(isEditable && isInput)
? TextField(
autofocus: false,
controller: controller,
@ -513,7 +519,7 @@ class ItemListWidget {
String buttonText = '分析详情'
}) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
padding: const EdgeInsets.symmetric(vertical: vertical_inset, horizontal: horizontal_inset),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -545,7 +551,11 @@ class ItemListWidget {
CustomButton(
text: buttonText,
height: 30,
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
padding: const EdgeInsets.symmetric(
vertical: 2,
horizontal: 10,
),
textStyle: TextStyle(color: Colors.white, fontSize: 11, fontWeight: FontWeight.bold),
backgroundColor: Colors.green,
onPressed: onTap,
),
@ -565,7 +575,7 @@ class ItemListWidget {
bool isRequired = false,
}) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
padding: const EdgeInsets.symmetric(vertical: vertical_inset, horizontal: horizontal_inset),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -605,7 +615,7 @@ class ItemListWidget {
void Function(String)? onTapCallBack,
}) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
padding: const EdgeInsets.symmetric(vertical: vertical_inset, horizontal: horizontal_inset),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -661,7 +671,7 @@ class ItemListWidget {
children: [
//
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 12),
padding: const EdgeInsets.symmetric(vertical: vertical_inset, horizontal: horizontal_inset),
child: Text(
title,
style: TextStyle(
@ -735,7 +745,7 @@ class ItemListWidget {
bool isRequired = true,
}) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
padding: const EdgeInsets.symmetric(vertical: vertical_inset, horizontal: horizontal_inset),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -814,14 +824,14 @@ class ItemListWidget {
);
}
static Widget itemContainer(Widget child, {double horizontal = 12}) {
static Widget itemContainer(Widget child, {double horizontal = horizontal_inset}) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.symmetric(horizontal: horizontal, vertical: 8),
padding: EdgeInsets.symmetric(horizontal: horizontal, vertical: vertical_inset),
child: child,
);
}

View File

@ -155,11 +155,13 @@ class _DangerousOptionsPageState extends State<DangerousOptionsPage> {
}
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final String path = await Navigator.push(
context,
MaterialPageRoute(builder: (c) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
final imageData = SignImageData(

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import '../../../../../../tools/tools.dart';
import '../../../item_list_widget.dart';
@ -12,6 +13,19 @@ class HotWorkDetailFormWidget extends StatefulWidget {
final VoidCallback onChooseHotworkUser;
final VoidCallback onAnalyzeTap;
//
final VoidCallback? onChooseVideoManager;
///
final VoidCallback? onWorkStartTimeHandle;
final VoidCallback? onWorkEndTimeHandle;
///
final VoidCallback? onContractorHandle;
///
final VoidCallback? onWorkAreaHandle;
///
final VoidCallback? onWorkAreaLocationHandle;
///
final TextEditingController? contentController;
final TextEditingController? locationController;
@ -27,6 +41,14 @@ class HotWorkDetailFormWidget extends StatefulWidget {
required this.onChooseLevel,
required this.onChooseHotworkUser,
required this.onAnalyzeTap,
///
this.onChooseVideoManager,
this.onWorkStartTimeHandle,
this.onWorkEndTimeHandle,
this.onContractorHandle,
this.onWorkAreaHandle,
this.onWorkAreaLocationHandle,
this.contentController,
this.locationController,
this.methodController,
@ -34,25 +56,31 @@ class HotWorkDetailFormWidget extends StatefulWidget {
this.relatedController,
this.riskController,
}) : assert(
!isEditable ||
(contentController != null &&
locationController != null &&
methodController != null &&
hotworkPersonController != null &&
relatedController != null &&
riskController != null),
'Editable mode requires all TextEditingController parameters',
),
super(key: key);
!isEditable ||
(contentController != null &&
locationController != null &&
methodController != null &&
hotworkPersonController != null &&
relatedController != null &&
riskController != null),
'Editable mode requires all TextEditingController parameters',
),
super(key: key);
@override
State<HotWorkDetailFormWidget> createState() => _HotWorkDetailFormWidgetState();
State<HotWorkDetailFormWidget> createState() =>
_HotWorkDetailFormWidgetState();
}
class _HotWorkDetailFormWidgetState extends State<HotWorkDetailFormWidget> {
bool IS_CONTRACTOR_WORK = false;
@override
Widget build(BuildContext context) {
if (FormUtils.hasValue(widget.pd, 'LATITUDE')) {
widget.pd['LATITUDE_LONGITUDE'] = '${widget.pd['LATITUDE']},${widget.pd['LONGITUDE']}'; //map
}
final pd = widget.pd;
return Container(
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: const BoxDecoration(
@ -102,6 +130,7 @@ class _HotWorkDetailFormWidgetState extends State<HotWorkDetailFormWidget> {
onTap: widget.onChooseLevel,
text: pd['WORK_LEVEL'] ?? '',
),
const Divider(),
ItemListWidget.singleLineTitleText(
label: '动火方式:',
@ -127,21 +156,22 @@ class _HotWorkDetailFormWidgetState extends State<HotWorkDetailFormWidget> {
),
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '关联其他特殊作业及安全作业票编号',
label: '关联其他特殊作业及安全作业票编号',
isEditable: widget.isEditable,
onTap: () async {
final val = await showDialog<String>(
await showDialog<String>(
context: context,
builder: (_) => SelectionPopup(
type: 'assignments',
initialValue: pd['SPECIAL_WORK'] ?? '',
onConfirm: (val) {
setState(() {
pd['SPECIAL_WORK'] = val;
widget.relatedController?.text = val;
});
},
),
builder:
(_) => SelectionPopup(
type: 'assignments',
initialValue: pd['SPECIAL_WORK'] ?? '',
onConfirm: (val) {
setState(() {
pd['SPECIAL_WORK'] = val;
widget.relatedController?.text = val;
});
},
),
);
FocusHelper.clearFocus(context);
},
@ -151,21 +181,22 @@ class _HotWorkDetailFormWidgetState extends State<HotWorkDetailFormWidget> {
),
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '风险辨识结果',
label: '风险辨识结果',
isEditable: widget.isEditable,
onTap: () async {
await showDialog<String>(
context: context,
builder: (_) => SelectionPopup(
type: 'identification',
initialValue: pd['RISK_IDENTIFICATION'] ?? '',
onConfirm: (val) {
setState(() {
pd['RISK_IDENTIFICATION'] = val;
widget.riskController?.text = val;
});
},
),
builder:
(_) => SelectionPopup(
type: 'identification',
initialValue: pd['RISK_IDENTIFICATION'] ?? '',
onConfirm: (val) {
setState(() {
pd['RISK_IDENTIFICATION'] = val;
widget.riskController?.text = val;
});
},
),
);
FocusHelper.clearFocus(context);
},
@ -173,6 +204,77 @@ class _HotWorkDetailFormWidgetState extends State<HotWorkDetailFormWidget> {
controller: widget.riskController,
text: pd['RISK_IDENTIFICATION'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '视频监控:',
isClean: pd['WORK_LEVEL'] == '一级' || pd['WORK_LEVEL'] == '二级',
cleanText: '清除监控',
isRequired: pd['WORK_LEVEL'] == '特级',
isEditable: widget.isEditable,
onTap: widget.onChooseVideoManager ?? () {},
text: pd['VIDEONAME'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '预计作业开始时间:',
isEditable: widget.isEditable,
onTap: widget.onWorkStartTimeHandle ?? () {},
text: pd['WORK_EXPECTED_START_TIME'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '预计作业结束时间:',
isEditable: widget.isEditable,
onTap: widget.onWorkEndTimeHandle ?? () {},
text: pd['WORK_EXPECTED_END_TIME'] ?? '',
),
const Divider(),
ListItemFactory.createYesNoSection(
verticalPadding: 0,
horizontalPadding: 0,
title: '是否承包商作业',
isEdit: widget.isEditable,
text: widget.pd['IS_CONTRACTOR_WORK'] == '1' ? '' : '',
isRequired: true,
groupValue: widget.pd['IS_CONTRACTOR_WORK'] == '1',
onChanged: (bool value) {
setState(() {
widget.pd['IS_CONTRACTOR_WORK'] = value ? '1' : "0";
});
},
),
if (pd['IS_CONTRACTOR_WORK'] == '1')
Column(
children: [
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '承包商:',
isEditable: widget.isEditable,
onTap: widget.onContractorHandle ?? () {},
text: pd['UNITS_NAME'] ?? '',
),
],
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '作业区域:',
isEditable: widget.isEditable,
onTap: widget.onWorkAreaHandle ?? () {},
text: pd['PLS_NAME'] ?? '',
),
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '作业地点经纬度',
isInput: false,
isEditable: widget.isEditable,
buttonText: '定位',
onTap: widget.onWorkAreaLocationHandle ?? (){},
hintText: '',
text: pd['LATITUDE_LONGITUDE'] ?? (widget.isEditable ? '' : ''),
),
if (FormUtils.hasValue(pd, 'ANALYZE_TIME')) ...[
const Divider(),
ItemListWidget.OneRowButtonTitleText(

View File

@ -41,12 +41,10 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
///
late Map<String, dynamic> pd = {};
late List<Map<String, dynamic>> measuresList = [];
///
final TextEditingController _otherController = TextEditingController();
///
late List<dynamic> workUserList = [];
///
List<String> imagePaths = [];
List<String> signTimes = []; //
@ -54,7 +52,6 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
void initState() {
super.initState();
_getData();
_getHotWorkNameList();
}
///
@ -65,8 +62,7 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
barrierColor: Colors.black54,
backgroundColor: Colors.transparent,
builder:
(_) =>
DepartmentPicker(
(_) => DepartmentPicker(
onSelected: (id, name) async {
setState(() {
item.DEPARTMENT_ID = id;
@ -88,15 +84,15 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
});
}
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
FocusHelper.clearFocus(context);
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
@ -111,60 +107,61 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
Widget _signListWidget() {
return Column(
children:
imagePaths.map((path) {
return Column(
children: [
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
imagePaths.map((path) {
return Column(
children: [
GestureDetector(
child: // ConstrainedBox BoxFit.contain
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
imagePaths.remove(path);
});
},
GestureDetector(
child: // ConstrainedBox BoxFit.contain
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
imagePaths.remove(path);
});
},
),
),
const SizedBox(height: 80),
],
),
const SizedBox(height: 80),
],
),
],
),
],
);
}).toList(),
);
}).toList(),
);
}
bool _validateAndProceed(BuildContext context) {
for (var i = 0; i < measuresList.length; i++) {
final m = measuresList[i];
@ -178,10 +175,9 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
// STATUS == '1' ANSWER
if (m['STATUS'] == '1') {
for (var j = 1; j <= 4; j++) {
if (FormUtils.hasValue(m, 'QUESTION${j}')
) {
if (!FormUtils.hasValue(m, 'ANSWER${j}')
|| (m['ANSWER${j}'] as String?)!.length == 0) {
if (FormUtils.hasValue(m, 'QUESTION${j}')) {
if (!FormUtils.hasValue(m, 'ANSWER${j}') ||
(m['ANSWER${j}'] as String?)!.length == 0) {
ToastUtil.showNormal(context, '${i + 1}项未填写第${j}');
return false;
}
@ -191,7 +187,8 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
}
return true;
}
/// 1 0
/// 1 0
Future<void> _submit(String status) async {
if (_otherController.text.trim().isEmpty) {
ToastUtil.showNormal(context, '请输入其他安全措施,没有请填“无”');
@ -205,14 +202,13 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
if (status == '1') {
if (!_validateAndProceed(context)) {
return;
return;
}
} else {
await showDialog<String>(
context: context,
builder:
(_) =>
CustomAlertDialog(
(_) => CustomAlertDialog(
title: '作废原因',
mode: DialogMode.input,
hintText: '请输入作废原因',
@ -241,8 +237,7 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
await showDialog<String>(
context: context,
builder:
(_) =>
CustomAlertDialog(
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
@ -250,7 +245,8 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
onConfirm: () async {
LoadingDialogHelper.show();
try {
final result = await ApiService.saveSafeFunctionSure('hotwork',
final result = await ApiService.saveSafeFunctionSure(
'hotwork',
formData,
imagePaths,
);
@ -260,7 +256,7 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
context,
status == '1' ? '提交成功' : '已暂存',
);
Navigator.pop(context);
Navigator.of(context).pop(true); // true
}
} catch (e) {
LoadingDialogHelper.hide();
@ -278,16 +274,12 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
}
}
Future<void> _getHotWorkNameList() async {
final result = await ApiService.getHotWorkNameList();
setState(() {
workUserList = result['varList'] ?? '';
});
}
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById('hotwork', widget.HOTWORK_ID);
final data = await ApiService.getHomeworkFindById(
'hotwork',
widget.HOTWORK_ID,
);
setState(() {
pd = data['pd'];
_getMeasures();
@ -295,7 +287,10 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
}
Future<void> _getMeasures() async {
final data = await ApiService.listSignSureAllMeasures('hotwork',widget.HOTWORK_ID);
final data = await ApiService.listSignSureAllMeasures(
'hotwork',
widget.HOTWORK_ID,
);
setState(() {
measuresList = List<Map<String, dynamic>>.from(
data['measuresForSignList'] ?? <Map<String, dynamic>>[],
@ -303,7 +298,6 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
});
}
Future<void> _itemToSign(Map<String, dynamic> measures, int index) async {
//
final List<Map<String, dynamic>> signImgList = measures['SIGN_ITEM'] ?? [];
@ -312,44 +306,54 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
final List<ImageData> imgList = [];
if ((measures['IMG_PATH'] as String?)?.isNotEmpty ?? false) {
for (var path in (measures['IMG_PATH'] as String).split(',')) {
imgList.add(ImageData(localPath:path, serverPath: path));
imgList.add(ImageData(localPath: path, serverPath: path));
}
}
//measures['STATUS']
final result = await pushPage(DangerousOptionsPage(index: index,status: int.parse(FormUtils.hasValue(measures, 'STATUS') ? measures['STATUS'] : '1'),
measures: measures['PROTECTIVE_MEASURES'] ?? '',
imgList: imgList,
signImgList: signImgList), context);
final result = await pushPage(
DangerousOptionsPage(
index: index,
status: int.parse(
FormUtils.hasValue(measures, 'STATUS') ? measures['STATUS'] : '1',
),
measures: measures['PROTECTIVE_MEASURES'] ?? '',
imgList: imgList,
signImgList: signImgList,
),
context,
);
if (result != null) {
setState(() {
// local + remote
final returned = result['imgList'] as List<dynamic>;
// ImageData
final imgDataList = returned.map((m) {
return ImageData(
localPath: m['local'] as String,
serverPath: m['remote'] as String,
);
}).toList();
final imgDataList =
returned.map((m) {
return ImageData(
localPath: m['local'] as String,
serverPath: m['remote'] as String,
);
}).toList();
// serverPath
final serverPathString = imgDataList
.map((e) => e.serverPath)
.where((s) => s.isNotEmpty)
.map((s) => s) // String? String
.map((s) => s) // String? String
.join(',');
// measures
measures['IMG_PATH'] = serverPathString;
//
measures['SIGN_ITEM'] = List<Map<String,dynamic>>.from(result['signImgList'] as List);
measures['SIGN_ITEM'] = List<Map<String, dynamic>>.from(
result['signImgList'] as List,
);
//
measures['STATUS'] = result['status'].toString();
index = result['index'] as int;
});
}
}
///
@ -370,8 +374,7 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
Container(
color: Colors.white,
child: MeasuresListWidget(
measuresList:
measuresList, // List<Map<String, dynamic>>
measuresList: measuresList, // List<Map<String, dynamic>>
baseImgPath: ApiService.baseImgPath,
isAllowEdit: true,
onSign: (item) {
@ -381,11 +384,12 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
),
],
),
ItemListWidget.singleLineTitleText(label: '其他安全措施:',
isEditable: true,
hintText: '请输入其他安全措施',
controller
:_otherController),
ItemListWidget.singleLineTitleText(
label: '其他安全措施:',
isEditable: true,
hintText: '请输入其他安全措施',
controller: _otherController,
),
SizedBox(height: 20),
Row(
@ -492,9 +496,8 @@ class MeasureItem {
List<Map<String, dynamic>>? userList,
this.userIndex = -1,
List<Map<String, dynamic>>? selectMeasures,
})
: userList = userList ?? [],
selectMeasures = selectMeasures ?? [];
}) : userList = userList ?? [],
selectMeasures = selectMeasures ?? [];
Map<String, dynamic> toJson() {
return {

View File

@ -51,13 +51,14 @@ class _HotworkAqglDetailState extends State<HotworkAqglDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
@ -187,7 +188,7 @@ class _HotworkAqglDetailState extends State<HotworkAqglDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -79,13 +79,14 @@ class _HotworkAqjdDetailState extends State<HotworkAqjdDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
@ -217,7 +218,7 @@ class _HotworkAqjdDetailState extends State<HotworkAqjdDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -53,13 +53,14 @@ class _HotworkDbbzDetailState extends State<HotworkDbbzDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
@ -190,7 +191,7 @@ class _HotworkDbbzDetailState extends State<HotworkDbbzDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -1,13 +1,17 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/BaiDuMap/Map_page.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.dart';
import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.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/home/tap/tabList/special_wrok/dh_work/HotWorkDetailFormWidget.dart';
import 'package:qhd_prevention/pages/home/tap/workArea_picker.dart';
import 'package:qhd_prevention/tools/h_colors.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:qhd_prevention/http/ApiService.dart';
@ -16,12 +20,12 @@ import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/qtfx_
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/MeasuresListWidget.dart';
enum EditUserType {
ANALYZE('分析单位', '分析单位负责人', true),
GUARDIAN('监护人单位', '监护人', true),
CONFESS('安全交底人单位', '安全交底人', true),
ACCEPT_CONFESS('接受交底人单位', '接受交底人', true),
WORK_USER('作业人单位', '作业人', true),
CONFIRM('作业负责人单位', '作业负责人', true),
LEADER('所在单位', '所在单位负责人', true),
AUDIT('安全管理部门', '安全管理部门负责人', true),
@ -39,7 +43,6 @@ enum EditUserType {
const EditUserType(this.displayName, this.personName, this.isRequired);
}
class HotworkApplyDetail extends StatefulWidget {
const HotworkApplyDetail({
super.key,
@ -77,6 +80,15 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
///
late List<dynamic> workUserList = [];
/// ------------------- -------------------
///
late List<dynamic> videoMonitoringList = [];
///
late List<dynamic> unitAllList = [];
///
late List<Map<String, dynamic>> workAreaList = [];
/// --------------------------------------
//
final Map<EditUserType, List<Map<String, dynamic>>> _personCache = {};
@ -96,6 +108,9 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
pd['APPLY_USER_NAME'] = SessionService.instance.username;
}
_getHotWorkNameList();
_getVideoList();
_getUnitListAll();
_getPlsList();
_contentController.addListener(() {
setState(() {
@ -128,7 +143,11 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
}
void set_pd_USER_ID(EditUserType type, String id) {
pd['${type.name}_USER_ID'] = id;
if (type == EditUserType.WORK_USER) {
pd['${type.name}_ID'] = id;
}else{
pd['${type.name}_USER_ID'] = id;
}
}
void set_pd_USER_Name(EditUserType type, String name) {
@ -144,7 +163,11 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
}
String get_pd_USER_ID(EditUserType type) {
return pd['${type.name}_USER_ID'] ?? '';
if (type == EditUserType.WORK_USER) {
return pd['${type.name}_ID'] ?? '';
} else {
return pd['${type.name}_USER_ID'] ?? '';
}
}
String get_pd_USER_Name(EditUserType type) {
@ -190,6 +213,153 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
}
}
/// ---------------------------- --------------------------------
///
Future<void> _chooseVideoManager() async {
final choice = await BottomPicker.show<String>(
context,
items:
videoMonitoringList
.map((item) => item['VIDEONAME'] as String)
.toList(),
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
initialIndex: 0,
);
if (choice != null) {
setState(() {
pd['VIDEONAME'] = choice;
Map<String, dynamic> result = videoMonitoringList.firstWhere(
(item) => item['VIDEONAME'] == choice,
orElse: () => {}, //
);
if (FormUtils.hasValue(result, 'VIDEOMANAGER_ID')) {
pd['VIDEOMANAGER_ID'] = result['VIDEOMANAGER_ID'];
}
FocusHelper.clearFocus(context);
});
}
}
///
Future<void> _chooseUnitManager() async {
final choice = await BottomPicker.show<String>(
context,
items: unitAllList.map((item) => item['UNITS_NAME'] as String).toList(),
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
initialIndex: 0,
);
if (choice != null) {
setState(() {
pd['UNITS_NAME'] = choice;
Map<String, dynamic> result = unitAllList.firstWhere(
(item) => item['UNITS_NAME'] == choice,
orElse: () => {}, //
);
if (FormUtils.hasValue(result, 'UNITS_ID')) {
pd['UNITS_ID'] = result['UNITS_ID'];
}
FocusHelper.clearFocus(context);
});
}
}
///
Future<void> _chooseWorkStartTime() async {
DateTime? picked = await BottomDateTimePicker.showDate(
context,
allowFuture: true,
);
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_START_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
).format(picked);
///
if (FormUtils.hasValue(pd, 'WORK_EXPECTED_END_TIME') &&
!isBeforeStr(
pd['WORK_EXPECTED_START_TIME'],
pd['WORK_EXPECTED_END_TIME'],
)) {
pd['WORK_EXPECTED_END_TIME'] = '';
}
});
}
}
///
Future<void> _chooseWorkEndTime() async {
DateTime? picked = await BottomDateTimePicker.showDate(
context,
minTimeStr: pd['WORK_EXPECTED_START_TIME'] ?? '',
allowFuture: true,
);
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_END_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
).format(picked);
});
}
}
///
Future<void> _showLocationHandle() async{
if (!FormUtils.hasValue(pd, 'ELECTRONIC_FENCE_AREA_ID')) {
ToastUtil.showNormal(context, '请选择作业区域');
return;
}
Map mapData = await pushPage(MapPage(gson: pd['POSITIONS']), context);
setState(() {
pd['LONGITUDE'] = mapData['longitue'];
pd['LATITUDE'] = mapData['latitude'];
pd['LATITUDE_LONGITUDE'] = '${mapData['longitue']},${mapData['latitude']}';
});
}
///
Future<void> _getWorkArea() async {
FocusHelper.clearFocus(context);
showModalBottomSheet(
context: context,
isScrollControlled: true,
barrierColor: Colors.black54,
backgroundColor: Colors.transparent,
builder:
(_) => WorkAreaPicker(
onSelected: (String id, String POSITIONS, String name) {
pd['ELECTRONIC_FENCE_AREA_ID'] = id;
pd['POSITIONS'] = POSITIONS;
pd['PLS_NAME'] = name;
},
),
).then((_) {
FocusHelper.clearFocus(context);
});
}
///
Future<void> _getVideoList() async {
final result = await ApiService.getVideomanagerList();
setState(() {
videoMonitoringList = result['varList'] ?? [];
});
}
///
Future<void> _getUnitListAll() async {
final result = await ApiService.getUnitListAll();
setState(() {
unitAllList = result['varList'] ?? [];
});
}
///
Future<void> _getPlsList() async {
final result = await ApiService.getWorkAreaList();
setState(() {
final String zTreeNodes = result['zTreeNodes'] ?? '';
workAreaList = jsonDecode(zTreeNodes);
});
}
/// ------------------------------------------------------------
Widget _card(Widget child) {
return Container(
padding: EdgeInsets.symmetric(vertical: 5),
@ -211,14 +381,13 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
isRequired = false;
}
// APPROVE
if (type == EditUserType.APPROVE && pd['WORK_LEVEL'] != '特级') {
isRequired = false;
isClean = true;
}
// EditUserType.APPROVE,
if (type == EditUserType.APPROVE &&
// APPROVE
if (type == EditUserType.APPROVE && pd['WORK_LEVEL'] != '特级') {
isRequired = false;
isClean = true;
}
// EditUserType.APPROVE,
if (type == EditUserType.APPROVE &&
((pd['WORK_LEVEL'] ?? '') == '二级' ||
(pd['WORK_LEVEL'] ?? '') == '一级')) {
isClean = true;
@ -301,13 +470,15 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
return;
}
if (personList.isEmpty) { //
if (personList.isEmpty) {
//
await _getPersonListForUnitId(unitId, type);
final list = _personCache[type] ?? [];
if (list.isEmpty) { //
if (list.isEmpty) {
//
ToastUtil.showNormal(context, '暂无数据,请选择其他单位');
}else{
} else {
choosePersonHandle(type);
}
return;
@ -355,14 +526,15 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
EditUserType.GUARDIAN,
EditUserType.CONFESS,
EditUserType.ACCEPT_CONFESS,
EditUserType.WORK_USER,
EditUserType.CONFIRM,
EditUserType.LEADER,
// SAFETY_USER_ID AUDIT
if (pd['WORK_LEVEL'] != '二级' || FormUtils.hasValue(pd, 'SAFETY_USER_ID')) EditUserType.AUDIT,
if (pd['WORK_LEVEL'] != '二级' || FormUtils.hasValue(pd, 'SAFETY_USER_ID'))
EditUserType.AUDIT,
EditUserType.AUDIT,
// APPROVE
if (pd['WORK_LEVEL'] == '特级')
EditUserType.APPROVE,
if (pd['WORK_LEVEL'] == '特级') EditUserType.APPROVE,
EditUserType.MONITOR,
EditUserType.WORK_START,
@ -383,6 +555,30 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
ToastUtil.showNormal(context, '请选择动火级别');
return;
}
if (level == '特级') {
if (!FormUtils.hasValue(pd, 'VIDEOMANAGER_ID')) {
ToastUtil.showNormal(context, '请选择视频监控');
return;
}
}
if (!FormUtils.hasValue(pd, 'WORK_EXPECTED_START_TIME')) {
ToastUtil.showNormal(context, '请选择预计作业开始时间');
return;
}
if (!FormUtils.hasValue(pd, 'WORK_EXPECTED_START_TIME')) {
ToastUtil.showNormal(context, '请选择预计作业开始时间');
return;
}
if (pd['IS_CONTRACTOR_WORK'] == '1' && !FormUtils.hasValue(pd, 'UNITS_ID')) {
ToastUtil.showNormal(context, '请选择承包商');
return;
}
if (!FormUtils.hasValue(pd, 'LATITUDE_LONGITUDE')) {
ToastUtil.showNormal(context, '请定位作业地点');
return;
}
for (var type in unitRules) {
if (get_pd_DEPARTMENT_ID(type).length == 0) {
@ -433,10 +629,9 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, status == '1' ? '提交成功' : '已暂存');
Navigator.pop(context);
}else{
Navigator.of(context).pop(true);
} else {
ToastUtil.showSuccess(context, '提交失败');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -447,15 +642,20 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
Future<void> _getHotWorkNameList() async {
final result = await ApiService.getHotWorkNameList();
setState(() {
workUserList = result['varList'] ?? '';
List<String> names =
workUserList.map((item) => item['NAME'] as String).toList();
workUserList = result['varList'] ?? [];
});
}
/// ---------------------------- --------------------------------
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById('hotwork', widget.HOTWORK_ID);
final data = await ApiService.getHomeworkFindById(
'hotwork',
widget.HOTWORK_ID,
);
setState(() {
pd = data['pd'];
if (pd['STEP_ID'] == 0) {
@ -478,18 +678,18 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
// });
// LoadingDialogHelper.hide();
}
Future<void> _getSigns(String homework_id) async {
final data = await ApiService.listSignFinished('hotwork',
final data = await ApiService.listSignFinished(
'hotwork',
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
signs = data['signs'] ?? {};
});
}
Future<void> _getMeasures(String homework_id) async {
final data = await ApiService.listSignFinishMeasures('hotwork',
final data = await ApiService.listSignFinishMeasures(
'hotwork',
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
@ -521,6 +721,14 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
riskController: _riskController,
onChooseLevel: _chooseLevel,
onChooseHotworkUser: _chooseHorkUser,
//
onChooseVideoManager: _chooseVideoManager,
onWorkStartTimeHandle: _chooseWorkStartTime,
onWorkEndTimeHandle: _chooseWorkEndTime,
onContractorHandle: _chooseUnitManager,
onWorkAreaHandle: _getWorkArea,
onWorkAreaLocationHandle: _showLocationHandle,
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
@ -541,6 +749,8 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
SizedBox(height: 15),
_card(_chooseItem(EditUserType.ACCEPT_CONFESS)),
SizedBox(height: 15),
_card(_chooseItem(EditUserType.WORK_USER)),
SizedBox(height: 15),
_card(_chooseItem(EditUserType.CONFIRM)),
SizedBox(height: 15),
_card(_chooseItem(EditUserType.LEADER)),
@ -604,7 +814,7 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
color: Colors.white,
child: MeasuresListWidget(
measuresList:
measuresList, // List<Map<String, dynamic>>
measuresList, // List<Map<String, dynamic>>
baseImgPath: ApiService.baseImgPath,
isAllowEdit: false,
),
@ -632,45 +842,9 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
),
isEditable
? Row(
spacing: 10,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: CustomButton(
height: 45,
textStyle: TextStyle(
fontSize: 16,
color: Colors.white,
),
text: '提交',
backgroundColor: Colors.blue,
onPressed: () {
_submit('1');
},
),
),
Expanded(
child: CustomButton(
textStyle: TextStyle(
fontSize: 16,
color: Colors.white,
),
text: '暂存',
backgroundColor: Colors.green,
onPressed: () {
_submit('0');
},
),
),
],
)
: Column(
children: [
SizedBox(height: 20),
Row(
spacing: 10,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(width: 50),
Expanded(
child: CustomButton(
height: 45,
@ -678,18 +852,54 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
fontSize: 16,
color: Colors.white,
),
text: '返回',
backgroundColor: Colors.green,
text: '提交',
backgroundColor: Colors.blue,
onPressed: () {
Navigator.pop(context);
_submit('1');
},
),
),
SizedBox(width: 50),
Expanded(
child: CustomButton(
textStyle: TextStyle(
fontSize: 16,
color: Colors.white,
),
text: '暂存',
backgroundColor: Colors.green,
onPressed: () {
_submit('0');
},
),
),
],
)
: Column(
children: [
SizedBox(height: 20),
Row(
children: [
SizedBox(width: 50),
Expanded(
child: CustomButton(
height: 45,
textStyle: TextStyle(
fontSize: 16,
color: Colors.white,
),
text: '返回',
backgroundColor: Colors.green,
onPressed: () {
Navigator.pop(context);
},
),
),
SizedBox(width: 50),
],
),
],
),
],
),
],
),
),

View File

@ -50,13 +50,14 @@ class _HotworkDhspDetailState extends State<HotworkDhspDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
@ -187,7 +188,7 @@ class _HotworkDhspDetailState extends State<HotworkDhspDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -13,7 +13,9 @@ import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/szaq_
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/szdw_work_detail/hotwork_szdw_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/ysgd_work_detail/hotwork_ysgd_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/zyfz_work_detail/hotwork_zyfz_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/work_area_helper.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/services/location_service.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
@ -159,9 +161,15 @@ class _HotWorkListPageState extends State<HotWorkListPage> {
}
}
void _goToDetail(Map<String, dynamic> item) async {
final Map<String, dynamic> data = {'HOTWORK_ID': item['HOTWORK_ID'], 'flow': widget.flow};
String routeName = '';
final allowed = await WorkAreaHelper.checkInSpecialWorkArea(
context: context,
flow: widget.flow,
areaId: item['ELECTRONIC_FENCE_AREA_ID'] ?? '',
);
if (!allowed) return;
switch (widget.flow) {
case '提交申请':
await pushPage(HotworkApplyDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
@ -177,71 +185,55 @@ class _HotWorkListPageState extends State<HotWorkListPage> {
await pushPage(HotworkSafeFuncSure(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '监护人签字':
routeName = '/hotwork-guardian-detail';
await pushPage(HotworkJhrDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '安全交底人签字':
routeName = '/hotwork-confess-detail';
await pushPage(HotworkAqjdDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '接受交底人签字':
routeName = '/hotwork-acceptconfess-detail';
await pushPage(HotworkJsjdDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '作业负责人签字':
routeName = '/hotwork-confirm-detail';
await pushPage(HotworkZyfzDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '所在单位签字':
routeName = '/hotwork-leader-detail';
await pushPage(HotworkSzdwDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '安全管理部门签字':
routeName = '/hotwork-audit-detail';
await pushPage(HotworkAqglDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '审批人签字':
routeName = '/hotwork-approve-detail';
await pushPage(HotworkDhspDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '当班班长验票':
routeName = '/hotwork-monitor-detail';
await pushPage(HotworkDbbzDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '开始作业':
routeName = '/hotwork-startwork-detail';
await pushPage(HotworkKszyDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '结束作业':
routeName = '/hotwork-endwork-detail';
await pushPage(HotworkJszyDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '验收签字':
routeName = '/hotwork-accept-detail';
await pushPage(HotworkYsgdDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
default:
routeName = '/hotwork-detail';
break;
}
setState(() {
_fetchSteps();
_fetchData();
});
// Navigator.pushNamed(
// context,
// routeName,
// arguments: {'HOTWORK_ID': item['HOTWORK_ID'], 'flow': widget.flow},
// );
}
Widget _buildFlowStepItem({

View File

@ -47,13 +47,14 @@ class _HotworkJhrDetailState extends State<HotworkJhrDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
imagePaths.add(path);
signTimes.add(now);
@ -180,7 +181,7 @@ class _HotworkJhrDetailState extends State<HotworkJhrDetail> {
context,
'保存成功',
);
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -47,13 +47,14 @@ class _HotworkJsjdDetailState extends State<HotworkJsjdDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
@ -178,7 +179,7 @@ class _HotworkJsjdDetailState extends State<HotworkJsjdDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -52,13 +52,14 @@ class _HotworkJszyDetailState extends State<HotworkJszyDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
@ -223,7 +224,7 @@ class _HotworkJszyDetailState extends State<HotworkJszyDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -52,13 +52,14 @@ class _HotworkKszyDetailState extends State<HotworkKszyDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
@ -195,7 +196,7 @@ class _HotworkKszyDetailState extends State<HotworkKszyDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -18,6 +18,7 @@ import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/dh_work/szaq_work_detail/SafeFunctionDialog.dart';
///
class HotworkSetSafeDetail extends StatefulWidget {
const HotworkSetSafeDetail({
@ -57,8 +58,6 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
return jsonEncode(jsonList);
}
Widget _chooseItem(MeasureItem item) {
return Column(
children: [
@ -83,9 +82,9 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
onTap: () {
showSafeFunctionDialog(
context,
_getAvailableMeasures(item), //
initialSelected: item.selectMeasures, //
(selected) {
_getAvailableMeasures(item), //
initialSelected: item.selectMeasures, //
(selected) {
setState(() {
item.selectMeasures = selected;
});
@ -163,10 +162,13 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
FocusHelper.clearFocus(context);
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
@ -249,17 +251,11 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
int index = 0;
for (var item in measuresListCopy) {
if (item.USER_ID.isEmpty) {
ToastUtil.showNormal(
context,
'${index + 1}项未设置确认人',
);
ToastUtil.showNormal(context, '${index + 1}项未设置确认人');
return;
}
if (item.selectMeasures.isEmpty) {
ToastUtil.showNormal(
context,
'${index + 1}项未选择安全措施',
);
ToastUtil.showNormal(context, '${index + 1}项未选择安全措施');
return;
}
final userId = item.USER_ID;
@ -310,37 +306,35 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
formData['STEP_REASON'] = reasonText;
formData['PREPARERS'] = json.encode(signers);
printLongString('submit---:${json.encode(formData)}');
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
onConfirm: () async {
LoadingDialogHelper.show();
try {
final result = await ApiService.saveSafeFunctionSure(
'hotwork',
formData,
imagePaths,
);
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(
context,
'保存成功',
);
Navigator.pop(context);
}
} catch (e) {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, '操作失败:$e');
}
},
),
final confirmed = await CustomAlertDialog.showConfirm(
context,
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
barrierDismissible: false,
);
if (confirmed) {
LoadingDialogHelper.show();
try {
final result = await ApiService.saveSafeFunctionSure(
'hotwork',
formData,
imagePaths,
);
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
} else {
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, '操作失败:$e');
}
}
}
void printLongString(String text, {int chunkSize = 800}) {
@ -352,7 +346,10 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById('hotwork', widget.HOTWORK_ID);
final data = await ApiService.getHomeworkFindById(
'hotwork',
widget.HOTWORK_ID,
);
setState(() {
pd = data['pd'];
_getMeasures();
@ -390,6 +387,7 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
);
});
}
/// item
List<Map<String, dynamic>> _getAvailableMeasures(MeasureItem current) {
// current ID
@ -401,17 +399,18 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
}
}
// measuresList ID usedIds current
List<Map<String, dynamic>> list = measuresList.where((m) {
final id = m['BUS_HOTWORK_MEASURES_ID'];
final isCurrentSelected = current.selectMeasures
.any((sm) => sm['BUS_HOTWORK_MEASURES_ID'] == id);
return !usedIds.contains(id) || isCurrentSelected;
}).toList();
List<Map<String, dynamic>> list =
measuresList.where((m) {
final id = m['BUS_HOTWORK_MEASURES_ID'];
final isCurrentSelected = current.selectMeasures.any(
(sm) => sm['BUS_HOTWORK_MEASURES_ID'] == id,
);
return !usedIds.contains(id) || isCurrentSelected;
}).toList();
return list;
}
///
Widget _setSafeDetailWidget() {
return Container(
@ -570,8 +569,8 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
HotWorkDetailFormWidget(
pd: pd,
isEditable: false,
onChooseLevel: (){},
onChooseHotworkUser: (){},
onChooseLevel: () {},
onChooseHotworkUser: () {},
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),

View File

@ -50,13 +50,14 @@ class _HotworkSzdwDetailState extends State<HotworkSzdwDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
@ -187,7 +188,7 @@ class _HotworkSzdwDetailState extends State<HotworkSzdwDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -85,13 +85,14 @@ class _HotworkYsgdDetailState extends State<HotworkYsgdDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
@ -248,7 +249,7 @@ class _HotworkYsgdDetailState extends State<HotworkYsgdDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -50,13 +50,14 @@ class _HotworkZyfzDetailState extends State<HotworkZyfzDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
@ -187,7 +188,7 @@ class _HotworkZyfzDetailState extends State<HotworkZyfzDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -20,6 +20,18 @@ class CutroadDetailFormWidget extends StatefulWidget {
final TextEditingController? contentController; //
final TextEditingController? relatedController;
final TextEditingController? riskController;
//
final VoidCallback? onChooseVideoManager;
///
final VoidCallback? onWorkStartTimeHandle;
final VoidCallback? onWorkEndTimeHandle;
///
final VoidCallback? onContractorHandle;
///
final VoidCallback? onWorkAreaHandle;
///
final VoidCallback? onWorkAreaLocationHandle;
///
final signs;
@ -28,6 +40,15 @@ class CutroadDetailFormWidget extends StatefulWidget {
required this.pd,
required this.isEditable,
required this.onChooseLevel,
///
this.onChooseVideoManager,
this.onWorkStartTimeHandle,
this.onWorkEndTimeHandle,
this.onContractorHandle,
this.onWorkAreaHandle,
this.onWorkAreaLocationHandle,
this.unitController,
this.contentController,
this.relatedController,
@ -225,7 +246,11 @@ class _CutroadDetailFormWidgetState extends State<CutroadDetailFormWidget> {
}
@override
Widget build(BuildContext context) {
if (FormUtils.hasValue(widget.pd, 'LATITUDE')) {
widget.pd['LATITUDE_LONGITUDE'] = '${widget.pd['LATITUDE']},${widget.pd['LONGITUDE']}'; //map
}
final pd = widget.pd;
return Container(
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: const BoxDecoration(
@ -283,9 +308,78 @@ class _CutroadDetailFormWidgetState extends State<CutroadDetailFormWidget> {
),
const Divider(),
],
ItemListWidget.selectableLineTitleTextRightButton(
label: '视频监控:',
isClean: true,
cleanText: '清除监控',
isRequired: false,
isEditable: widget.isEditable,
onTap: widget.onChooseVideoManager ?? () {},
text: pd['VIDEONAME'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '预计作业开始时间:',
isEditable: widget.isEditable,
onTap: widget.onWorkStartTimeHandle ?? () {},
text: pd['WORK_EXPECTED_START_TIME'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '预计作业结束时间:',
isEditable: widget.isEditable,
onTap: widget.onWorkEndTimeHandle ?? () {},
text: pd['WORK_EXPECTED_END_TIME'] ?? '',
),
const Divider(),
ListItemFactory.createYesNoSection(
verticalPadding: 0,
horizontalPadding: 0,
title: '是否承包商作业',
isEdit: widget.isEditable,
text: widget.pd['IS_CONTRACTOR_WORK'] == '1' ? '' : '',
isRequired: true,
groupValue: widget.pd['IS_CONTRACTOR_WORK'] == '1',
onChanged: (bool value) {
setState(() {
widget.pd['IS_CONTRACTOR_WORK'] = value ? '1' : "0";
});
},
),
if (pd['IS_CONTRACTOR_WORK'] == '1')
Column(
children: [
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '承包商:',
isEditable: widget.isEditable,
onTap: widget.onContractorHandle ?? () {},
text: pd['UNITS_NAME'] ?? '',
),
],
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '作业区域:',
isEditable: widget.isEditable,
onTap: widget.onWorkAreaHandle ?? () {},
text: pd['PLS_NAME'] ?? '',
),
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '作业地点经纬度',
isInput: false,
isEditable: widget.isEditable,
buttonText: '定位',
onTap: widget.onWorkAreaLocationHandle ?? (){},
hintText: '',
text: pd['LATITUDE_LONGITUDE'] ?? '',
),
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '关联其他特殊作业及安全作业票编号:',
label: '关联其他特殊作业及安全作业票编号',
isEditable: widget.isEditable,
onTap: () async {
final val = await showDialog<String>(
@ -309,7 +403,7 @@ class _CutroadDetailFormWidgetState extends State<CutroadDetailFormWidget> {
),
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '风险辨识结果',
label: '风险辨识结果',
isEditable: widget.isEditable,
onTap: () async {
await showDialog<String>(

View File

@ -42,8 +42,7 @@ class _CutroadSafeFuncSureState extends State<CutroadSafeFuncSure> {
///
final TextEditingController _otherController = TextEditingController();
///
late List<dynamic> workUserList = [];
///
List<String> imagePaths = [];
@ -52,7 +51,7 @@ class _CutroadSafeFuncSureState extends State<CutroadSafeFuncSure> {
void initState() {
super.initState();
_getData();
_getHotWorkNameList();
}
///
@ -90,14 +89,15 @@ class _CutroadSafeFuncSureState extends State<CutroadSafeFuncSure> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
FocusHelper.clearFocus(context);
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
imagePaths.add(path);
signTimes.add(now);
@ -259,7 +259,7 @@ class _CutroadSafeFuncSureState extends State<CutroadSafeFuncSure> {
context,
status == '1' ? '提交成功' : '已暂存',
);
Navigator.pop(context);
Navigator.of(context).pop(true); // true
}
} catch (e) {
LoadingDialogHelper.hide();
@ -277,12 +277,7 @@ class _CutroadSafeFuncSureState extends State<CutroadSafeFuncSure> {
}
}
Future<void> _getHotWorkNameList() async {
final result = await ApiService.getHotWorkNameList();
setState(() {
workUserList = result['varList'] ?? '';
});
}
///
Future<void> _getData() async {

View File

@ -78,13 +78,14 @@ class _CutroadAqjdDetailState extends State<CutroadAqjdDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
@ -217,7 +218,7 @@ class _CutroadAqjdDetailState extends State<CutroadAqjdDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -14,6 +14,7 @@ import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dl_work/szdw_
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dl_work/ysgd_work_detail/cutroad_ysgd_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dl_work/zyfz_work_detail/cutroad_zyfz_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dl_work/zyr_work_detail/cutroad_zyr_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/work_area_helper.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
@ -167,10 +168,12 @@ class _CutroadListPageState extends State<CutroadListPage> {
}
void _goToDetail(Map<String, dynamic> item) async {
final Map<String, dynamic> data = {
'CUTROAD_ID': item['CUTROAD_ID'],
'flow': widget.flow,
};
final allowed = await WorkAreaHelper.checkInSpecialWorkArea(
context: context,
flow: widget.flow,
areaId: item['ELECTRONIC_FENCE_AREA_ID'] ?? '',
);
if (!allowed) return;
switch (widget.flow) {
case '提交申请':
await pushPage(CutroadApplyDetail(CUTROAD_ID: item['CUTROAD_ID'], flow: widget.flow), context);

View File

@ -1,10 +1,12 @@
import 'dart:convert';
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/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.dart';
import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.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/home/tap/tabList/special_wrok/dl_work/CutroadDetailFormWidget.dart';
@ -14,6 +16,8 @@ import 'package:qhd_prevention/http/ApiService.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/MeasuresListWidget.dart';
import 'package:qhd_prevention/customWidget/BaiDuMap/Map_page.dart';
import 'package:qhd_prevention/pages/home/tap/workArea_picker.dart';
enum EditUserType {
@ -65,9 +69,15 @@ class _CutroadApplyDetailState extends State<CutroadApplyDetail> {
final TextEditingController _contentController = TextEditingController();
final TextEditingController _relatedController = TextEditingController();
final TextEditingController _riskController = TextEditingController();
/// ------------------- -------------------
///
late List<dynamic> videoMonitoringList = [];
///
late List<dynamic> unitAllList = [];
///
late List<Map<String, dynamic>> workAreaList = [];
/// --------------------------------------
///
late List<dynamic> workUserList = [];
//
final Map<EditUserType, List<Map<String, dynamic>>> _personCache = {};
@ -86,8 +96,10 @@ class _CutroadApplyDetailState extends State<CutroadApplyDetail> {
pd['APPLY_USER_ID'] = SessionService.instance.loginUserId;
pd['APPLY_USER_NAME'] = SessionService.instance.username;
}
_getHotWorkNameList();
_getVideoList();
_getUnitListAll();
_getPlsList();
_contentController.addListener(() {
setState(() {
pd['WORK_REASON'] = _contentController.text.trim();
@ -296,6 +308,24 @@ class _CutroadApplyDetailState extends State<CutroadApplyDetail> {
}
}
if (!FormUtils.hasValue(pd, 'WORK_EXPECTED_START_TIME')) {
ToastUtil.showNormal(context, '请选择预计作业开始时间');
return;
}
if (!FormUtils.hasValue(pd, 'WORK_EXPECTED_END_TIME')) {
ToastUtil.showNormal(context, '请选择预计作业结束时间');
return;
}
if (pd['IS_CONTRACTOR_WORK'] == '1' && !FormUtils.hasValue(pd, 'UNITS_ID')) {
ToastUtil.showNormal(context, '请选择承包商');
return;
}
if (!FormUtils.hasValue(pd, 'LATITUDE_LONGITUDE')) {
ToastUtil.showNormal(context, '请定位作业地点');
return;
}
for (var type in unitRules) {
if (get_pd_DEPARTMENT_ID(type).length == 0) {
@ -307,6 +337,7 @@ class _CutroadApplyDetailState extends State<CutroadApplyDetail> {
return;
}
}
}
// LoadingDialogHelper.show();
@ -342,7 +373,7 @@ class _CutroadApplyDetailState extends State<CutroadApplyDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, status == '1' ? '提交成功' : '已暂存');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();
@ -357,14 +388,152 @@ class _CutroadApplyDetailState extends State<CutroadApplyDetail> {
}
}
Future<void> _getHotWorkNameList() async {
final result = await ApiService.getHotWorkNameList();
/// ---------------------------- --------------------------------
///
Future<void> _chooseVideoManager() async {
final choice = await BottomPicker.show<String>(
context,
items:
videoMonitoringList
.map((item) => item['VIDEONAME'] as String)
.toList(),
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
initialIndex: 0,
);
if (choice != null) {
setState(() {
pd['VIDEONAME'] = choice;
Map<String, dynamic> result = videoMonitoringList.firstWhere(
(item) => item['VIDEONAME'] == choice,
orElse: () => {}, //
);
if (FormUtils.hasValue(result, 'VIDEOMANAGER_ID')) {
pd['VIDEOMANAGER_ID'] = result['VIDEOMANAGER_ID'];
}
FocusHelper.clearFocus(context);
});
}
}
///
Future<void> _chooseUnitManager() async {
final choice = await BottomPicker.show<String>(
context,
items: unitAllList.map((item) => item['UNITS_NAME'] as String).toList(),
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
initialIndex: 0,
);
if (choice != null) {
setState(() {
pd['UNITS_NAME'] = choice;
Map<String, dynamic> result = unitAllList.firstWhere(
(item) => item['UNITS_NAME'] == choice,
orElse: () => {}, //
);
if (FormUtils.hasValue(result, 'UNITS_ID')) {
pd['UNITS_ID'] = result['UNITS_ID'];
}
FocusHelper.clearFocus(context);
});
}
}
///
Future<void> _chooseWorkStartTime() async {
DateTime? picked = await BottomDateTimePicker.showDate(
context,
allowFuture: true,
);
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_START_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
).format(picked);
///
if (FormUtils.hasValue(pd, 'WORK_EXPECTED_END_TIME') &&
!isBeforeStr(
pd['WORK_EXPECTED_START_TIME'],
pd['WORK_EXPECTED_END_TIME'],
)) {
pd['WORK_EXPECTED_END_TIME'] = '';
}
});
}
}
///
Future<void> _chooseWorkEndTime() async {
DateTime? picked = await BottomDateTimePicker.showDate(
context,
minTimeStr: pd['WORK_EXPECTED_START_TIME'] ?? '',
allowFuture: true,
);
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_END_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
).format(picked);
});
}
}
///
Future<void> _showLocationHandle() async{
if (!FormUtils.hasValue(pd, 'ELECTRONIC_FENCE_AREA_ID')) {
ToastUtil.showNormal(context, '请选择作业区域');
return;
}
Map mapData = await pushPage(MapPage(gson: pd['POSITIONS']), context);
setState(() {
workUserList = result['varList'] ?? '';
List<String> names =
workUserList.map((item) => item['NAME'] as String).toList();
pd['LONGITUDE'] = mapData['longitue'];
pd['LATITUDE'] = mapData['latitude'];
pd['LATITUDE_LONGITUDE'] = '${mapData['longitue']},${mapData['latitude']}';
});
}
///
Future<void> _getWorkArea() async {
FocusHelper.clearFocus(context);
showModalBottomSheet(
context: context,
isScrollControlled: true,
barrierColor: Colors.black54,
backgroundColor: Colors.transparent,
builder:
(_) => WorkAreaPicker(
onSelected: (String id, String POSITIONS, String name) {
pd['ELECTRONIC_FENCE_AREA_ID'] = id;
pd['POSITIONS'] = POSITIONS;
pd['PLS_NAME'] = name;
},
),
).then((_) {
FocusHelper.clearFocus(context);
});
}
///
Future<void> _getVideoList() async {
final result = await ApiService.getVideomanagerList();
setState(() {
videoMonitoringList = result['varList'] ?? [];
});
}
///
Future<void> _getUnitListAll() async {
final result = await ApiService.getUnitListAll();
setState(() {
unitAllList = result['varList'] ?? [];
});
}
///
Future<void> _getPlsList() async {
final result = await ApiService.getWorkAreaList();
setState(() {
final String zTreeNodes = result['zTreeNodes'] ?? '';
workAreaList = jsonDecode(zTreeNodes);
});
}
/// ------------------------------------------------------------
///
Future<void> _getData() async {
@ -431,6 +600,13 @@ class _CutroadApplyDetailState extends State<CutroadApplyDetail> {
relatedController: _relatedController,
riskController: _riskController,
onChooseLevel: (){},
//
onChooseVideoManager: _chooseVideoManager,
onWorkStartTimeHandle: _chooseWorkStartTime,
onWorkEndTimeHandle: _chooseWorkEndTime,
onContractorHandle: _chooseUnitManager,
onWorkAreaHandle: _getWorkArea,
onWorkAreaLocationHandle: _showLocationHandle,
),
),
if (isEditable)

View File

@ -49,13 +49,14 @@ class _CutroadJhrDetailState extends State<CutroadJhrDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
imagePaths.add(path);
signTimes.add(now);
@ -182,7 +183,7 @@ class _CutroadJhrDetailState extends State<CutroadJhrDetail> {
context,
'保存成功',
);
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -50,14 +50,15 @@ class _CutroadJsjdDetailState extends State<CutroadJsjdDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -181,7 +182,7 @@ class _CutroadJsjdDetailState extends State<CutroadJsjdDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -52,13 +52,14 @@ class _CutroadJszyDetailState extends State<CutroadJszyDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
@ -136,26 +137,7 @@ class _CutroadJszyDetailState extends State<CutroadJszyDetail> {
return false;
}
// 8 8 * 60 * 60 * 1000 ms
if (pd['WORK_LEVEL'] == '特级' || pd['WORK_LEVEL'] == '一级') {
final diffMs = end.difference(start).inMilliseconds;
const max8h = 8 * 60 * 60 * 1000;
if (diffMs >= max8h) {
ToastUtil.showNormal(context, '动火级别为特级或一级时动火作业开始时间与结束时间应不超过8小时请重新选择');
return false;
}
}
// 72 72 * 60 * 60 * 1000 ms
if (pd['WORK_LEVEL'] == '二级') {
final diffMs = end.difference(start).inMilliseconds;
const max72h = 72 * 60 * 60 * 1000;
if (diffMs >= max72h) {
ToastUtil.showNormal(context, '动火级别为二级时动火作业开始时间与结束时间应不超过72小时请重新选择');
return false;
}
}
return true;
}
/// -1 1
@ -223,7 +205,7 @@ class _CutroadJszyDetailState extends State<CutroadJszyDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -54,14 +54,15 @@ class _CutroadKszyDetailState extends State<CutroadKszyDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -190,7 +191,7 @@ class _CutroadKszyDetailState extends State<CutroadKszyDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -50,14 +50,15 @@ class _CutroadShbmDetailState extends State<CutroadShbmDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -187,7 +188,7 @@ class _CutroadShbmDetailState extends State<CutroadShbmDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -49,14 +49,15 @@ class _CutroadSpbmDetailState extends State<CutroadSpbmDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -186,7 +187,7 @@ class _CutroadSpbmDetailState extends State<CutroadSpbmDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -163,13 +163,14 @@ class _CutroadSetSafeDetailState extends State<CutroadSetSafeDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
imagePaths.add(path);
signTimes.add(now);
@ -332,7 +333,7 @@ class _CutroadSetSafeDetailState extends State<CutroadSetSafeDetail> {
context,
'保存成功',
);
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -50,14 +50,15 @@ class _CutroadSzdwDetailState extends State<CutroadSzdwDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -187,7 +188,7 @@ class _CutroadSzdwDetailState extends State<CutroadSzdwDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -81,14 +81,15 @@ class _CutroadYsgdDetailState extends State<CutroadYsgdDetail> {
}
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -244,7 +245,7 @@ class _CutroadYsgdDetailState extends State<CutroadYsgdDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -50,14 +50,15 @@ class _CutroadZyfzDetailState extends State<CutroadZyfzDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -187,7 +188,7 @@ class _CutroadZyfzDetailState extends State<CutroadZyfzDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -59,14 +59,15 @@ class _CutroadZyrDetailState extends State<CutroadZyrDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -206,7 +207,7 @@ class _CutroadZyrDetailState extends State<CutroadZyrDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -22,6 +22,17 @@ class BreakgroundDetailFormWidget extends StatefulWidget {
final TextEditingController? contentController; //
final TextEditingController? relatedController;
final TextEditingController? riskController;
//
final VoidCallback? onChooseVideoManager;
///
final VoidCallback? onWorkStartTimeHandle;
final VoidCallback? onWorkEndTimeHandle;
///
final VoidCallback? onContractorHandle;
///
final VoidCallback? onWorkAreaHandle;
///
final VoidCallback? onWorkAreaLocationHandle;
const BreakgroundDetailFormWidget({
Key? key,
@ -29,6 +40,14 @@ class BreakgroundDetailFormWidget extends StatefulWidget {
required this.isEditable,
required this.onChooseLevel,
required this.signs,
///
this.onChooseVideoManager,
this.onWorkStartTimeHandle,
this.onWorkEndTimeHandle,
this.onContractorHandle,
this.onWorkAreaHandle,
this.onWorkAreaLocationHandle,
this.locationController,
this.contentController,
this.relatedController,
@ -254,7 +273,11 @@ class _BreakgroundDetailFormWidgetState
@override
Widget build(BuildContext context) {
if (FormUtils.hasValue(widget.pd, 'LATITUDE')) {
widget.pd['LATITUDE_LONGITUDE'] = '${widget.pd['LATITUDE']},${widget.pd['LONGITUDE']}'; //map
}
final pd = widget.pd;
return Container(
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: const BoxDecoration(
@ -333,9 +356,79 @@ class _BreakgroundDetailFormWidgetState
),),
const Divider(),
],
ItemListWidget.selectableLineTitleTextRightButton(
label: '视频监控:',
isClean: true,
cleanText: '清除监控',
isRequired: false,
isEditable: widget.isEditable,
onTap: widget.onChooseVideoManager ?? () {},
text: pd['VIDEONAME'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '预计作业开始时间:',
isEditable: widget.isEditable,
onTap: widget.onWorkStartTimeHandle ?? () {},
text: pd['WORK_EXPECTED_START_TIME'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '预计作业结束时间:',
isEditable: widget.isEditable,
onTap: widget.onWorkEndTimeHandle ?? () {},
text: pd['WORK_EXPECTED_END_TIME'] ?? '',
),
const Divider(),
ListItemFactory.createYesNoSection(
verticalPadding: 0,
horizontalPadding: 0,
title: '是否承包商作业',
isEdit: widget.isEditable,
text: widget.pd['IS_CONTRACTOR_WORK'] == '1' ? '' : '',
isRequired: true,
groupValue: widget.pd['IS_CONTRACTOR_WORK'] == '1',
onChanged: (bool value) {
setState(() {
widget.pd['IS_CONTRACTOR_WORK'] = value ? '1' : "0";
});
},
),
if (pd['IS_CONTRACTOR_WORK'] == '1')
Column(
children: [
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '承包商:',
isEditable: widget.isEditable,
onTap: widget.onContractorHandle ?? () {},
text: pd['UNITS_NAME'] ?? '',
),
],
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '作业区域:',
isEditable: widget.isEditable,
onTap: widget.onWorkAreaHandle ?? () {},
text: pd['PLS_NAME'] ?? '',
),
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '关联其他特殊作业及安全作业票编号:',
label: '作业地点经纬度',
isInput: false,
isEditable: widget.isEditable,
buttonText: '定位',
onTap: widget.onWorkAreaLocationHandle ?? (){},
hintText: '',
text: pd['LATITUDE_LONGITUDE'] ?? '',
),
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '关联其他特殊作业及安全作业票编号',
isEditable: widget.isEditable,
onTap: () async {
final val = await showDialog<String>(
@ -360,7 +453,7 @@ class _BreakgroundDetailFormWidgetState
),
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '风险辨识结果',
label: '风险辨识结果',
isEditable: widget.isEditable,
onTap: () async {
await showDialog<String>(
@ -383,6 +476,7 @@ class _BreakgroundDetailFormWidgetState
controller: widget.riskController,
text: pd['RISK_IDENTIFICATION'] ?? '',
),
//
if (FormUtils.hasValue(widget.signs, 'WORK_USER'))
Column(

View File

@ -43,8 +43,7 @@ class _BreakgroundSafeFuncSureState extends State<BreakgroundSafeFuncSure> {
final TextEditingController _otherController = TextEditingController();
late Map<String, dynamic> signs = {};
///
late List<dynamic> workUserList = [];
///
List<String> imagePaths = [];
@ -90,14 +89,15 @@ class _BreakgroundSafeFuncSureState extends State<BreakgroundSafeFuncSure> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
FocusHelper.clearFocus(context);
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
imagePaths.add(path);
signTimes.add(now);
@ -259,7 +259,7 @@ class _BreakgroundSafeFuncSureState extends State<BreakgroundSafeFuncSure> {
context,
status == '1' ? '提交成功' : '已暂存',
);
Navigator.pop(context);
Navigator.of(context).pop(true); // true
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -78,13 +78,14 @@ class _BreakgroundAqjdDetailState extends State<BreakgroundAqjdDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
@ -217,7 +218,7 @@ class _BreakgroundAqjdDetailState extends State<BreakgroundAqjdDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -15,6 +15,7 @@ import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dt_work/szdw_
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dt_work/ysgd_work_detail/breakground_ysgd_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dt_work/zyfz_work_detail/breakground_zyfz_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dt_work/zyr_work_detail/breakground_zyr_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/work_area_helper.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
@ -169,6 +170,12 @@ class _BreakgroundListPageState extends State<BreakgroundListPage> {
}
void _goToDetail(Map<String, dynamic> item) async {
final allowed = await WorkAreaHelper.checkInSpecialWorkArea(
context: context,
flow: widget.flow,
areaId: item['ELECTRONIC_FENCE_AREA_ID'] ?? '',
);
if (!allowed) return;
switch (widget.flow) {
case '提交申请':

View File

@ -14,6 +14,10 @@ import 'package:qhd_prevention/http/ApiService.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/MeasuresListWidget.dart';
import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/pages/home/tap/workArea_picker.dart';
import 'package:qhd_prevention/customWidget/BaiDuMap/Map_page.dart';
enum EditUserType {
@ -68,9 +72,15 @@ class _BreakgroundApplyDetailState extends State<BreakgroundApplyDetail> {
final TextEditingController _contentController = TextEditingController();
final TextEditingController _relatedController = TextEditingController();
final TextEditingController _riskController = TextEditingController();
/// ------------------- -------------------
///
late List<dynamic> videoMonitoringList = [];
///
late List<dynamic> unitAllList = [];
///
late List<Map<String, dynamic>> workAreaList = [];
/// --------------------------------------
///
late List<dynamic> workUserList = [];
//
final Map<EditUserType, List<Map<String, dynamic>>> _personCache = {};
@ -81,6 +91,7 @@ class _BreakgroundApplyDetailState extends State<BreakgroundApplyDetail> {
if (widget.BREAKGROUND_ID.length > 0) {
msg = 'edit';
_getData();
} else {
isEditable = true;
pd['APPLY_DEPARTMENT_ID'] = SessionService.instance.deptId;
@ -94,6 +105,9 @@ class _BreakgroundApplyDetailState extends State<BreakgroundApplyDetail> {
});
});
}
_getVideoList();
_getUnitListAll();
_getPlsList();
_contentController.addListener(() {
setState(() {
pd['JOB_CONTENT'] = _contentController.text.trim();
@ -152,7 +166,151 @@ class _BreakgroundApplyDetailState extends State<BreakgroundApplyDetail> {
String get_pd_USER_Name(EditUserType type) {
return pd['${type.name}_USER_NAME'] ?? '';
}
/// ---------------------------- --------------------------------
///
Future<void> _chooseVideoManager() async {
final choice = await BottomPicker.show<String>(
context,
items:
videoMonitoringList
.map((item) => item['VIDEONAME'] as String)
.toList(),
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
initialIndex: 0,
);
if (choice != null) {
setState(() {
pd['VIDEONAME'] = choice;
Map<String, dynamic> result = videoMonitoringList.firstWhere(
(item) => item['VIDEONAME'] == choice,
orElse: () => {}, //
);
if (FormUtils.hasValue(result, 'VIDEOMANAGER_ID')) {
pd['VIDEOMANAGER_ID'] = result['VIDEOMANAGER_ID'];
}
FocusHelper.clearFocus(context);
});
}
}
///
Future<void> _chooseUnitManager() async {
final choice = await BottomPicker.show<String>(
context,
items: unitAllList.map((item) => item['UNITS_NAME'] as String).toList(),
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
initialIndex: 0,
);
if (choice != null) {
setState(() {
pd['UNITS_NAME'] = choice;
Map<String, dynamic> result = unitAllList.firstWhere(
(item) => item['UNITS_NAME'] == choice,
orElse: () => {}, //
);
if (FormUtils.hasValue(result, 'UNITS_ID')) {
pd['UNITS_ID'] = result['UNITS_ID'];
}
FocusHelper.clearFocus(context);
});
}
}
///
Future<void> _chooseWorkStartTime() async {
DateTime? picked = await BottomDateTimePicker.showDate(
context,
allowFuture: true,
);
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_START_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
).format(picked);
///
if (FormUtils.hasValue(pd, 'WORK_EXPECTED_END_TIME') &&
!isBeforeStr(
pd['WORK_EXPECTED_START_TIME'],
pd['WORK_EXPECTED_END_TIME'],
)) {
pd['WORK_EXPECTED_END_TIME'] = '';
}
});
}
}
///
Future<void> _chooseWorkEndTime() async {
DateTime? picked = await BottomDateTimePicker.showDate(
context,
minTimeStr: pd['WORK_EXPECTED_START_TIME'] ?? '',
allowFuture: true,
);
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_END_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
).format(picked);
});
}
}
///
Future<void> _showLocationHandle() async{
if (!FormUtils.hasValue(pd, 'ELECTRONIC_FENCE_AREA_ID')) {
ToastUtil.showNormal(context, '请选择作业区域');
return;
}
Map mapData = await pushPage(MapPage(gson: pd['POSITIONS']), context);
setState(() {
pd['LONGITUDE'] = mapData['longitue'];
pd['LATITUDE'] = mapData['latitude'];
pd['LATITUDE_LONGITUDE'] = '${mapData['longitue']},${mapData['latitude']}';
});
}
///
Future<void> _getWorkArea() async {
FocusHelper.clearFocus(context);
showModalBottomSheet(
context: context,
isScrollControlled: true,
barrierColor: Colors.black54,
backgroundColor: Colors.transparent,
builder:
(_) => WorkAreaPicker(
onSelected: (String id, String POSITIONS, String name) {
pd['ELECTRONIC_FENCE_AREA_ID'] = id;
pd['POSITIONS'] = POSITIONS;
pd['PLS_NAME'] = name;
},
),
).then((_) {
FocusHelper.clearFocus(context);
});
}
///
Future<void> _getVideoList() async {
final result = await ApiService.getVideomanagerList();
setState(() {
videoMonitoringList = result['varList'] ?? [];
});
}
///
Future<void> _getUnitListAll() async {
final result = await ApiService.getUnitListAll();
setState(() {
unitAllList = result['varList'] ?? [];
});
}
///
Future<void> _getPlsList() async {
final result = await ApiService.getWorkAreaList();
setState(() {
final String zTreeNodes = result['zTreeNodes'] ?? '';
workAreaList = jsonDecode(zTreeNodes);
});
}
/// ------------------------------------------------------------
Future<void> _chooseLevel() async {
final choice = await BottomPicker.show<String>(
context,
@ -327,7 +485,24 @@ class _BreakgroundApplyDetailState extends State<BreakgroundApplyDetail> {
return;
}
}
if (!FormUtils.hasValue(pd, 'WORK_EXPECTED_START_TIME')) {
ToastUtil.showNormal(context, '请选择预计作业开始时间');
return;
}
if (!FormUtils.hasValue(pd, 'WORK_EXPECTED_END_TIME')) {
ToastUtil.showNormal(context, '请选择预计作业结束时间');
return;
}
if (pd['IS_CONTRACTOR_WORK'] == '1' && !FormUtils.hasValue(pd, 'UNITS_ID')) {
ToastUtil.showNormal(context, '请选择承包商');
return;
}
if (!FormUtils.hasValue(pd, 'LATITUDE_LONGITUDE')) {
ToastUtil.showNormal(context, '请定位作业地点');
return;
}
for (var type in unitRules) {
if (get_pd_DEPARTMENT_ID(type).length == 0) {
ToastUtil.showNormal(context, '请选择${type.displayName}');
@ -369,7 +544,7 @@ class _BreakgroundApplyDetailState extends State<BreakgroundApplyDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, status == '1' ? '提交成功' : '已暂存');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();
@ -451,6 +626,13 @@ class _BreakgroundApplyDetailState extends State<BreakgroundApplyDetail> {
relatedController: _relatedController,
riskController: _riskController,
onChooseLevel: _chooseLevel,
//
onChooseVideoManager: _chooseVideoManager,
onWorkStartTimeHandle: _chooseWorkStartTime,
onWorkEndTimeHandle: _chooseWorkEndTime,
onContractorHandle: _chooseUnitManager,
onWorkAreaHandle: _getWorkArea,
onWorkAreaLocationHandle: _showLocationHandle,
),
),
if (isEditable)

View File

@ -50,13 +50,14 @@ class _BreakgroundDzzhDetailState extends State<BreakgroundDzzhDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
@ -187,7 +188,7 @@ class _BreakgroundDzzhDetailState extends State<BreakgroundDzzhDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -49,13 +49,14 @@ class _BreakgroundJhrDetailState extends State<BreakgroundJhrDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
imagePaths.add(path);
signTimes.add(now);
@ -182,7 +183,7 @@ class _BreakgroundJhrDetailState extends State<BreakgroundJhrDetail> {
context,
'保存成功',
);
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -47,14 +47,15 @@ class _BreakgroundJsjdDetailState extends State<BreakgroundJsjdDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -178,7 +179,7 @@ class _BreakgroundJsjdDetailState extends State<BreakgroundJsjdDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -52,14 +52,15 @@ class _BreakgroundJszyDetailState extends State<BreakgroundJszyDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -136,26 +137,7 @@ class _BreakgroundJszyDetailState extends State<BreakgroundJszyDetail> {
return false;
}
// 8 8 * 60 * 60 * 1000 ms
if (pd['WORK_LEVEL'] == '特级' || pd['WORK_LEVEL'] == '一级') {
final diffMs = end.difference(start).inMilliseconds;
const max8h = 8 * 60 * 60 * 1000;
if (diffMs >= max8h) {
ToastUtil.showNormal(context, '动火级别为特级或一级时动火作业开始时间与结束时间应不超过8小时请重新选择');
return false;
}
}
// 72 72 * 60 * 60 * 1000 ms
if (pd['WORK_LEVEL'] == '二级') {
final diffMs = end.difference(start).inMilliseconds;
const max72h = 72 * 60 * 60 * 1000;
if (diffMs >= max72h) {
ToastUtil.showNormal(context, '动火级别为二级时动火作业开始时间与结束时间应不超过72小时请重新选择');
return false;
}
}
return true;
}
/// -1 1
@ -223,7 +205,7 @@ class _BreakgroundJszyDetailState extends State<BreakgroundJszyDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -54,14 +54,15 @@ class _BreakgroundKszyDetailState extends State<BreakgroundKszyDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -190,7 +191,7 @@ class _BreakgroundKszyDetailState extends State<BreakgroundKszyDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -50,14 +50,15 @@ class _BreakgroundShbmDetailState extends State<BreakgroundShbmDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -187,7 +188,7 @@ class _BreakgroundShbmDetailState extends State<BreakgroundShbmDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -49,14 +49,15 @@ class _BreakgroundSpbmDetailState extends State<BreakgroundSpbmDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -186,7 +187,7 @@ class _BreakgroundSpbmDetailState extends State<BreakgroundSpbmDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -49,14 +49,15 @@ class _BreakgroundSsrDetailState extends State<BreakgroundSsrDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -180,7 +181,7 @@ class _BreakgroundSsrDetailState extends State<BreakgroundSsrDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -164,13 +164,14 @@ class _BreakgroundSetSafeDetailState extends State<BreakgroundSetSafeDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
imagePaths.add(path);
signTimes.add(now);
@ -333,7 +334,7 @@ class _BreakgroundSetSafeDetailState extends State<BreakgroundSetSafeDetail> {
context,
'保存成功',
);
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -50,14 +50,15 @@ class _BreakgroundSzdwDetailState extends State<BreakgroundSzdwDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -187,7 +188,7 @@ class _BreakgroundSzdwDetailState extends State<BreakgroundSzdwDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -85,14 +85,15 @@ class _BreakgroundYsgdDetailState extends State<BreakgroundYsgdDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -248,7 +249,7 @@ class _BreakgroundYsgdDetailState extends State<BreakgroundYsgdDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -50,14 +50,15 @@ class _BreakgroundZyfzDetailState extends State<BreakgroundZyfzDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -187,7 +188,7 @@ class _BreakgroundZyfzDetailState extends State<BreakgroundZyfzDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -63,14 +63,15 @@ class _BreakgroundZyrDetailState extends State<BreakgroundZyrDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -204,7 +205,7 @@ class _BreakgroundZyrDetailState extends State<BreakgroundZyrDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -24,12 +24,32 @@ class HoistWorkDetailFormWidget extends StatefulWidget {
final TextEditingController? relatedController;
final TextEditingController? riskController;
//
final VoidCallback? onChooseVideoManager;
///
final VoidCallback? onWorkStartTimeHandle;
final VoidCallback? onWorkEndTimeHandle;
///
final VoidCallback? onContractorHandle;
///
final VoidCallback? onWorkAreaHandle;
///
final VoidCallback? onWorkAreaLocationHandle;
const HoistWorkDetailFormWidget({
Key? key,
required this.pd,
required this.isEditable,
required this.onChooseLevel,
required this.signs,
///
this.onChooseVideoManager,
this.onWorkStartTimeHandle,
this.onWorkEndTimeHandle,
this.onContractorHandle,
this.onWorkAreaHandle,
this.onWorkAreaLocationHandle,
this.locationController,
this.hightController,
this.nameController,
@ -239,7 +259,11 @@ class _HoistworkDetailFormWidgetState extends State<HoistWorkDetailFormWidget> {
@override
Widget build(BuildContext context) {
if (FormUtils.hasValue(widget.pd, 'LATITUDE')) {
widget.pd['LATITUDE_LONGITUDE'] = '${widget.pd['LATITUDE']},${widget.pd['LONGITUDE']}'; //map
}
final pd = widget.pd;
return Container(
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: const BoxDecoration(
@ -300,6 +324,7 @@ class _HoistworkDetailFormWidgetState extends State<HoistWorkDetailFormWidget> {
hintText: '请输入吊物内容',
text: pd['WORK_CONTENT'] ?? '',
),
if (!widget.isEditable && FormUtils.hasValue(pd, 'WORK_START_DATE')) ...[
ItemListWidget.singleLineTitleText(
label: '作业开始时间:',
@ -316,10 +341,78 @@ class _HoistworkDetailFormWidgetState extends State<HoistWorkDetailFormWidget> {
),
const Divider(),
],
ItemListWidget.selectableLineTitleTextRightButton(
label: '视频监控:',
isClean: true,
cleanText: '清除监控',
isRequired: false,
isEditable: widget.isEditable,
onTap: widget.onChooseVideoManager ?? () {},
text: pd['VIDEONAME'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '预计作业开始时间:',
isEditable: widget.isEditable,
onTap: widget.onWorkStartTimeHandle ?? () {},
text: pd['WORK_EXPECTED_START_TIME'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '预计作业结束时间:',
isEditable: widget.isEditable,
onTap: widget.onWorkEndTimeHandle ?? () {},
text: pd['WORK_EXPECTED_END_TIME'] ?? '',
),
const Divider(),
ListItemFactory.createYesNoSection(
verticalPadding: 0,
horizontalPadding: 0,
title: '是否承包商作业',
isEdit: widget.isEditable,
text: widget.pd['IS_CONTRACTOR_WORK'] == '1' ? '' : '',
isRequired: true,
groupValue: widget.pd['IS_CONTRACTOR_WORK'] == '1',
onChanged: (bool value) {
setState(() {
widget.pd['IS_CONTRACTOR_WORK'] = value ? '1' : "0";
});
},
),
if (pd['IS_CONTRACTOR_WORK'] == '1')
Column(
children: [
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '承包商:',
isEditable: widget.isEditable,
onTap: widget.onContractorHandle ?? () {},
text: pd['UNITS_NAME'] ?? '',
),
],
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '作业区域:',
isEditable: widget.isEditable,
onTap: widget.onWorkAreaHandle ?? () {},
text: pd['PLS_NAME'] ?? '',
),
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '作业地点经纬度',
isInput: false,
isEditable: widget.isEditable,
buttonText: '定位',
onTap: widget.onWorkAreaLocationHandle ?? (){},
hintText: '',
text: pd['LATITUDE_LONGITUDE'] ?? '',
),
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '关联其他特殊作业及安全作业票编号:',
label: '关联其他特殊作业及安全作业票编号',
isEditable: widget.isEditable,
onTap: () async {
final val = await showDialog<String>(
@ -343,7 +436,7 @@ class _HoistworkDetailFormWidgetState extends State<HoistWorkDetailFormWidget> {
),
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '风险辨识结果',
label: '风险辨识结果',
isEditable: widget.isEditable,
onTap: () async {
await showDialog<String>(

View File

@ -43,8 +43,7 @@ class _HoistworkSafeFuncSureState extends State<HoistworkSafeFuncSure> {
final TextEditingController _otherController = TextEditingController();
late Map<String, dynamic> signs = {};
///
late List<dynamic> workUserList = [];
///
List<String> imagePaths = [];
@ -90,14 +89,15 @@ class _HoistworkSafeFuncSureState extends State<HoistworkSafeFuncSure> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
FocusHelper.clearFocus(context);
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
imagePaths.add(path);
signTimes.add(now);
@ -259,7 +259,7 @@ class _HoistworkSafeFuncSureState extends State<HoistworkSafeFuncSure> {
context,
status == '1' ? '提交成功' : '已暂存',
);
Navigator.pop(context);
Navigator.of(context).pop(true); // true
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -78,14 +78,15 @@ class _HoistworkAqjdDetailState extends State<HoistworkAqjdDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -217,7 +218,7 @@ class _HoistworkAqjdDetailState extends State<HoistworkAqjdDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -14,6 +14,10 @@ import 'package:qhd_prevention/http/ApiService.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/MeasuresListWidget.dart';
import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/pages/home/tap/workArea_picker.dart';
import 'package:qhd_prevention/customWidget/BaiDuMap/Map_page.dart';
enum EditUserType {
@ -64,7 +68,14 @@ class _HoistworkApplyDetailState extends State<HoistworkApplyDetail> {
late Map<String, dynamic> pd = {};
late Map<String, dynamic> signs = {};
late List<Map<String, dynamic>> measuresList = [];
/// ------------------- -------------------
///
late List<dynamic> videoMonitoringList = [];
///
late List<dynamic> unitAllList = [];
///
late List<Map<String, dynamic>> workAreaList = [];
/// --------------------------------------
final TextEditingController _locationController = TextEditingController();
final TextEditingController _hightController = TextEditingController();
final TextEditingController _nameController = TextEditingController();
@ -72,8 +83,7 @@ class _HoistworkApplyDetailState extends State<HoistworkApplyDetail> {
final TextEditingController _relatedController = TextEditingController();
final TextEditingController _riskController = TextEditingController();
///
late List<dynamic> workUserList = [];
//
final Map<EditUserType, List<Map<String, dynamic>>> _personCache = {};
@ -92,6 +102,9 @@ class _HoistworkApplyDetailState extends State<HoistworkApplyDetail> {
pd['APPLY_USER_ID'] = SessionService.instance.loginUserId;
pd['APPLY_USER_NAME'] = SessionService.instance.username;
}
_getVideoList();
_getUnitListAll();
_getPlsList();
_contentController.addListener(() {
setState(() {
pd['WORK_CONTENT'] = _contentController.text.trim();
@ -114,7 +127,151 @@ class _HoistworkApplyDetailState extends State<HoistworkApplyDetail> {
pd['RISK_IDENTIFICATION'] = _riskController.text.trim();
});
}
/// ---------------------------- --------------------------------
///
Future<void> _chooseVideoManager() async {
final choice = await BottomPicker.show<String>(
context,
items:
videoMonitoringList
.map((item) => item['VIDEONAME'] as String)
.toList(),
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
initialIndex: 0,
);
if (choice != null) {
setState(() {
pd['VIDEONAME'] = choice;
Map<String, dynamic> result = videoMonitoringList.firstWhere(
(item) => item['VIDEONAME'] == choice,
orElse: () => {}, //
);
if (FormUtils.hasValue(result, 'VIDEOMANAGER_ID')) {
pd['VIDEOMANAGER_ID'] = result['VIDEOMANAGER_ID'];
}
FocusHelper.clearFocus(context);
});
}
}
///
Future<void> _chooseUnitManager() async {
final choice = await BottomPicker.show<String>(
context,
items: unitAllList.map((item) => item['UNITS_NAME'] as String).toList(),
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
initialIndex: 0,
);
if (choice != null) {
setState(() {
pd['UNITS_NAME'] = choice;
Map<String, dynamic> result = unitAllList.firstWhere(
(item) => item['UNITS_NAME'] == choice,
orElse: () => {}, //
);
if (FormUtils.hasValue(result, 'UNITS_ID')) {
pd['UNITS_ID'] = result['UNITS_ID'];
}
FocusHelper.clearFocus(context);
});
}
}
///
Future<void> _chooseWorkStartTime() async {
DateTime? picked = await BottomDateTimePicker.showDate(
context,
allowFuture: true,
);
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_START_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
).format(picked);
///
if (FormUtils.hasValue(pd, 'WORK_EXPECTED_END_TIME') &&
!isBeforeStr(
pd['WORK_EXPECTED_START_TIME'],
pd['WORK_EXPECTED_END_TIME'],
)) {
pd['WORK_EXPECTED_END_TIME'] = '';
}
});
}
}
///
Future<void> _chooseWorkEndTime() async {
DateTime? picked = await BottomDateTimePicker.showDate(
context,
minTimeStr: pd['WORK_EXPECTED_START_TIME'] ?? '',
allowFuture: true,
);
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_END_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
).format(picked);
});
}
}
///
Future<void> _showLocationHandle() async{
if (!FormUtils.hasValue(pd, 'ELECTRONIC_FENCE_AREA_ID')) {
ToastUtil.showNormal(context, '请选择作业区域');
return;
}
Map mapData = await pushPage(MapPage(gson: pd['POSITIONS']), context);
setState(() {
pd['LONGITUDE'] = mapData['longitue'];
pd['LATITUDE'] = mapData['latitude'];
pd['LATITUDE_LONGITUDE'] = '${mapData['longitue']},${mapData['latitude']}';
});
}
///
Future<void> _getWorkArea() async {
FocusHelper.clearFocus(context);
showModalBottomSheet(
context: context,
isScrollControlled: true,
barrierColor: Colors.black54,
backgroundColor: Colors.transparent,
builder:
(_) => WorkAreaPicker(
onSelected: (String id, String POSITIONS, String name) {
pd['ELECTRONIC_FENCE_AREA_ID'] = id;
pd['POSITIONS'] = POSITIONS;
pd['PLS_NAME'] = name;
},
),
).then((_) {
FocusHelper.clearFocus(context);
});
}
///
Future<void> _getVideoList() async {
final result = await ApiService.getVideomanagerList();
setState(() {
videoMonitoringList = result['varList'] ?? [];
});
}
///
Future<void> _getUnitListAll() async {
final result = await ApiService.getUnitListAll();
setState(() {
unitAllList = result['varList'] ?? [];
});
}
///
Future<void> _getPlsList() async {
final result = await ApiService.getWorkAreaList();
setState(() {
final String zTreeNodes = result['zTreeNodes'] ?? '';
workAreaList = jsonDecode(zTreeNodes);
});
}
/// ------------------------------------------------------------
void set_pd_DEPARTMENT_ID(EditUserType type, String id) {
pd['${type.name}_DEPARTMENT_ID'] = id;
}
@ -344,7 +501,24 @@ class _HoistworkApplyDetailState extends State<HoistworkApplyDetail> {
ToastUtil.showNormal(context, '请选择作业级别');
return;
}
if (!FormUtils.hasValue(pd, 'WORK_EXPECTED_START_TIME')) {
ToastUtil.showNormal(context, '请选择预计作业开始时间');
return;
}
if (!FormUtils.hasValue(pd, 'WORK_EXPECTED_END_TIME')) {
ToastUtil.showNormal(context, '请选择预计作业结束时间');
return;
}
if (pd['IS_CONTRACTOR_WORK'] == '1' && !FormUtils.hasValue(pd, 'UNITS_ID')) {
ToastUtil.showNormal(context, '请选择承包商');
return;
}
if (!FormUtils.hasValue(pd, 'LATITUDE_LONGITUDE')) {
ToastUtil.showNormal(context, '请定位作业地点');
return;
}
for (var type in unitRules) {
if (get_pd_DEPARTMENT_ID(type).length == 0) {
ToastUtil.showNormal(context, '请选择${type.displayName}');
@ -394,7 +568,7 @@ class _HoistworkApplyDetailState extends State<HoistworkApplyDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, status == '1' ? '提交成功' : '已暂存');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();
@ -479,6 +653,13 @@ class _HoistworkApplyDetailState extends State<HoistworkApplyDetail> {
relatedController: _relatedController,
riskController: _riskController,
onChooseLevel: _chooseLevel,
//
onChooseVideoManager: _chooseVideoManager,
onWorkStartTimeHandle: _chooseWorkStartTime,
onWorkEndTimeHandle: _chooseWorkEndTime,
onContractorHandle: _chooseUnitManager,
onWorkAreaHandle: _getWorkArea,
onWorkAreaLocationHandle: _showLocationHandle,
),
),
if (isEditable)

View File

@ -50,14 +50,15 @@ class _HoistworkDzzhDetailState extends State<HoistworkDzzhDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -187,7 +188,7 @@ class _HoistworkDzzhDetailState extends State<HoistworkDzzhDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -16,6 +16,7 @@ import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dz_work/szdw_
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dz_work/ysgd_work_detail/hoistwork_ysgd_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dz_work/zyfz_work_detail/hoistwork_zyfz_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dz_work/zyr_work_detail/hoistwork_zyr_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/work_area_helper.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
@ -170,7 +171,12 @@ class _HoistworkListPageState extends State<HoistworkListPage> {
}
void _goToDetail(Map<String, dynamic> item) async {
final allowed = await WorkAreaHelper.checkInSpecialWorkArea(
context: context,
flow: widget.flow,
areaId: item['ELECTRONIC_FENCE_AREA_ID'] ?? '',
);
if (!allowed) return;
switch (widget.flow) {
case '提交申请':
await pushPage(HoistworkApplyDetail(HOISTING_ID: item['HOISTING_ID'], flow: widget.flow), context);

View File

@ -49,13 +49,14 @@ class _HoistworkJhrDetailState extends State<HoistworkJhrDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
imagePaths.add(path);
signTimes.add(now);
@ -182,7 +183,7 @@ class _HoistworkJhrDetailState extends State<HoistworkJhrDetail> {
context,
'保存成功',
);
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -47,14 +47,15 @@ class _HoistworkJsjdDetailState extends State<HoistworkJsjdDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -178,7 +179,7 @@ class _HoistworkJsjdDetailState extends State<HoistworkJsjdDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -52,14 +52,15 @@ class _HoistworkJszyDetailState extends State<HoistworkJszyDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -136,26 +137,7 @@ class _HoistworkJszyDetailState extends State<HoistworkJszyDetail> {
return false;
}
// 8 8 * 60 * 60 * 1000 ms
if (pd['WORK_LEVEL'] == '特级' || pd['WORK_LEVEL'] == '一级') {
final diffMs = end.difference(start).inMilliseconds;
const max8h = 8 * 60 * 60 * 1000;
if (diffMs >= max8h) {
ToastUtil.showNormal(context, '动火级别为特级或一级时动火作业开始时间与结束时间应不超过8小时请重新选择');
return false;
}
}
// 72 72 * 60 * 60 * 1000 ms
if (pd['WORK_LEVEL'] == '二级') {
final diffMs = end.difference(start).inMilliseconds;
const max72h = 72 * 60 * 60 * 1000;
if (diffMs >= max72h) {
ToastUtil.showNormal(context, '动火级别为二级时动火作业开始时间与结束时间应不超过72小时请重新选择');
return false;
}
}
return true;
}
/// -1 1
@ -223,7 +205,7 @@ class _HoistworkJszyDetailState extends State<HoistworkJszyDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -54,14 +54,15 @@ class _HoistworkKszyDetailState extends State<HoistworkKszyDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -190,7 +191,7 @@ class _HoistworkKszyDetailState extends State<HoistworkKszyDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -50,14 +50,15 @@ class _HoistworkShbmDetailState extends State<HoistworkShbmDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -187,7 +188,7 @@ class _HoistworkShbmDetailState extends State<HoistworkShbmDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -49,14 +49,15 @@ class _HoistworkSpbmDetailState extends State<HoistworkSpbmDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -186,7 +187,7 @@ class _HoistworkSpbmDetailState extends State<HoistworkSpbmDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -49,14 +49,15 @@ class _HoistworkSsrDetailState extends State<HoistworkSsrDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -180,7 +181,7 @@ class _HoistworkSsrDetailState extends State<HoistworkSsrDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -164,13 +164,14 @@ class _HoistworkSetSafeDetailState extends State<HoistworkSetSafeDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
imagePaths.add(path);
signTimes.add(now);
@ -333,7 +334,7 @@ class _HoistworkSetSafeDetailState extends State<HoistworkSetSafeDetail> {
context,
'保存成功',
);
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -50,14 +50,15 @@ class _HoistworkSzdwDetailState extends State<HoistworkSzdwDetail> {
///
Future<void> _sign() async {
await NativeOrientation.setLandscape();
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
await NativeOrientation.setPortrait();
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
@ -187,7 +188,7 @@ class _HoistworkSzdwDetailState extends State<HoistworkSzdwDetail> {
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
Navigator.of(context).pop(true);
}
} catch (e) {
LoadingDialogHelper.hide();

Some files were not shown because too many files have changed in this diff Show More