Compare commits

..

No commits in common. "fb412d90e382a1aa5d0e94b964728f577f3ca6e3" and "2fcd538649aeebeb77ae96d6cd748b93174e3bee" have entirely different histories.

28 changed files with 1382 additions and 2294 deletions

View File

@ -14,7 +14,7 @@ if (keystorePropertiesFile.exists()) {
}
android {
namespace = "com.qysz.qgxgf"
namespace = "com.company.myapp2"
compileSdk = flutter.compileSdkVersion
ndkVersion = "28.1.13356709"
@ -30,7 +30,7 @@ android {
}
defaultConfig {
applicationId = "com.qysz.qgxgf"
applicationId = "com.company.myapp2"
minSdk = 24
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode

View File

@ -104,7 +104,7 @@
<!-- FileProvider 配置 -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.qysz.qgxgf.fileprovider"
android:authorities="com.company.myapp2.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data

View File

@ -0,0 +1,123 @@
package com.company.myapp2
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() {
private val CHANNEL = "app.install"
private val REQ_INSTALL_UNKNOWN = 9999
// 暂存安装请求(仅在跳转设置并等待返回时使用)
private var pendingApkPath: String? = null
private var pendingResult: MethodChannel.Result? = null
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
}
handleInstallRequest(path, result)
}
else -> result.notImplemented()
}
}
}
private fun handleInstallRequest(path: String, result: MethodChannel.Result) {
val file = File(path)
if (!file.exists()) {
result.error("NO_FILE", "file not exist", null)
return
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// 8.0+ 需要 app 级别未知来源授权
if (!packageManager.canRequestPackageInstalls()) {
// 存储请求信息以便用户返回后继续
pendingApkPath = path
pendingResult = result
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
Uri.parse("package:$packageName"))
// 使用 startActivityForResult 以便用户返回后可以继续安装
startActivityForResult(intent, REQ_INSTALL_UNKNOWN)
return
}
}
// 已有授权 或 非 8.0+:直接安装
installApkInternal(path, result)
}
// 真正执行安装的函数(假定有权限)
private fun installApkInternal(path: String, result: MethodChannel.Result) {
val file = File(path)
if (!file.exists()) {
result.error("NO_FILE", "file not exist", null)
return
}
try {
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)
} catch (e: Exception) {
result.error("INSTALL_FAILED", e.message, null)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQ_INSTALL_UNKNOWN) {
// 用户从系统设置页返回后,检查是否已授权
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (packageManager.canRequestPackageInstalls()) {
// 授权已开:继续安装
val path = pendingApkPath
val res = pendingResult
// 清理 pending 状态
pendingApkPath = null
pendingResult = null
if (path != null && res != null) {
installApkInternal(path, res)
} else {
// 安全兜底:若没有 pending 数据,通知 caller 重新触发
res?.error("NO_PENDING", "no pending install info", null)
}
} else {
// 用户仍未授权
pendingApkPath = null
pendingResult?.error("NEED_INSTALL_PERMISSION", "user did not allow install unknown apps", null)
pendingResult = null
}
} else {
// API < 26尝试直接安装一次作为尝试某些 ROM 无法精准判断)
val path = pendingApkPath
val res = pendingResult
pendingApkPath = null
pendingResult = null
if (path != null && res != null) {
installApkInternal(path, res)
} else {
res?.error("NO_PENDING", "no pending install info", null)
}
}
}
}
}

View File

@ -1,4 +1,4 @@
package com.qysz.qgxgf
package com.company.myapp2
import android.app.Application
import android.content.Context

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,581 +0,0 @@
{
"extValues": {},
"success": true,
"errCode": null,
"errMessage": null,
"exception": null,
"traceId": "18491030037470208",
"data": [
{
"extValues": {},
"id": "2030925300149387265",
"menuName": "首页",
"menuUrl": "/dashboard",
"parentId": "0",
"parentIds": null,
"menuPerms": "dashboard",
"menuType": 1,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 0,
"showFlag": 1,
"children": [
{
"extValues": {},
"id": "2030925300149387268",
"menuName": "单位管理",
"menuUrl": "/dashboard/Unit/Management",
"parentId": "2030925300149387265",
"parentIds": null,
"menuPerms": "dashboard-Unit-Management",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 3,
"showFlag": 1,
"children": [
{
"extValues": {},
"id": "2030925300149387286",
"menuName": "就职单位",
"menuUrl": "/dashboard/Unit/Management/Employment/Unit",
"parentId": "2030925300149387268",
"parentIds": null,
"menuPerms": "dashboard-Unit-Management-Employment-Unit",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 21,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387287",
"menuName": "服务单位管理",
"menuUrl": "/dashboard/Unit/Management/Managee/Service/Unit/Management",
"parentId": "2030925300149387268",
"parentIds": null,
"menuPerms": "dashboard-Unit-Management-Managee-Service-Unit-Management",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 22,
"showFlag": 1,
"children": null
}
]
},
{
"extValues": {},
"id": "2030925300149387269",
"menuName": "通知公告",
"menuUrl": "/dashboard/Notice/Announcement",
"parentId": "2030925300149387265",
"parentIds": null,
"menuPerms": "dashboard-Notice-Announcement",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 4,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387270",
"menuName": "口门门禁",
"menuUrl": "/dashboard/Gate/Access/Control",
"parentId": "2030925300149387265",
"parentIds": null,
"menuPerms": "dashboard-Gate-Access-Control",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 5,
"showFlag": 1,
"children": [
{
"extValues": {},
"id": "2030925300149387288",
"menuName": "进港口门申请",
"menuUrl": "/dashboard/Gate/Access/Control/Port/Gate/Entry/Application",
"parentId": "2030925300149387270",
"parentIds": null,
"menuPerms": "dashboard-Gate-Access-Control-Port-Gate-Entry-Application",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 23,
"showFlag": 1,
"children": [
{
"extValues": {},
"id": "2030925300149387292",
"menuName": "人员申请",
"menuUrl": "/dashboard/Port/Gate/Entry/Application/Personnel/Application",
"parentId": "2030925300149387288",
"parentIds": null,
"menuPerms": "dashboard-Port-Gate-Entry-Application-Personnel-Application",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 27,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387293",
"menuName": "车辆申请",
"menuUrl": "/dashboard/Port/Gate/Entry/Application/Vehicle/Application",
"parentId": "2030925300149387288",
"parentIds": null,
"menuPerms": "dashboard-Port-Gate-Entry-Application-Vehicle-Application",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 28,
"showFlag": 1,
"children": null
}
]
},
{
"extValues": {},
"id": "2030925300149387289",
"menuName": "进港口门申请记录",
"menuUrl": "/dashboard/Gate/Access/Crdtrol/Port/Gate/Entry/Record",
"parentId": "2030925300149387270",
"parentIds": null,
"menuPerms": "dashboard-Gate-Access-Crdtrol-Port-Gate-Entry-Record",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 24,
"showFlag": 1,
"children": [
{
"extValues": {},
"id": "2030925300149387294",
"menuName": "人员申请记录",
"menuUrl": "/dashboard/Port/Gate/Entry/Record/Record/Personnel/Application/Record",
"parentId": "2030925300149387289",
"parentIds": null,
"menuPerms": "dashboard-Port-Gate-Entry-Record-Record-Personnel-Application-Record",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 29,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387295",
"menuName": "车辆申请记录",
"menuUrl": "/dashboard/Port/Gate/Entry/Record/Record/Vehicle/Application/Record",
"parentId": "2030925300149387289",
"parentIds": null,
"menuPerms": "dashboard-Port-Gate-Entry-Record-Record-Vehicle-Application-Record",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 30,
"showFlag": 1,
"children": null
}
]
},
{
"extValues": {},
"id": "2030925300149387290",
"menuName": "封闭区域口门申请",
"menuUrl": "/dashboard/Area/Access/Cionsedrol/Closed/Area/Gate/Application",
"parentId": "2030925300149387270",
"parentIds": null,
"menuPerms": "dashboard-Area-Access-Cionsedrol-Closed-Area-Gate-Application",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 25,
"showFlag": 1,
"children": [
{
"extValues": {},
"id": "2030925300149387296",
"menuName": "人员申请",
"menuUrl": "/dashboard/Closed/Area/Gate/Application/Personnel/Application",
"parentId": "2030925300149387290",
"parentIds": null,
"menuPerms": "dashboard-Closed-Area-Gate-Application-Personnel-Application",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 31,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387297",
"menuName": "车辆申请",
"menuUrl": "/dashboard/Closed/Area/Gate/Application/Vehicle/Application",
"parentId": "2030925300149387290",
"parentIds": null,
"menuPerms": "dashboard-Closed-Area-Gate-Application-Vehicle-Application",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 32,
"showFlag": 1,
"children": null
}
]
},
{
"extValues": {},
"id": "2030925300149387291",
"menuName": "封闭区域口门申请记录",
"menuUrl": "/dashboard/Area/Access/Crdsedrol/Closed/Area/Gate/Record",
"parentId": "2030925300149387270",
"parentIds": null,
"menuPerms": "dashboard-Area-Access-Crdsedrol-Closed-Area-Gate-Record",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 26,
"showFlag": 1,
"children": [
{
"extValues": {},
"id": "2030925300149387298",
"menuName": "人员申请记录",
"menuUrl": "/dashboard/Closed/Area/Gate/Record/Record/Personnel/Application/Record",
"parentId": "2030925300149387291",
"parentIds": null,
"menuPerms": "dashboard-Closed-Area-Gate-Record-Record-Personnel-Application-Record",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 33,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387299",
"menuName": "车辆申请记录",
"menuUrl": "/dashboard/Closed/Area/Gate/Record/Record/Vehicle/Application/Record",
"parentId": "2030925300149387291",
"parentIds": null,
"menuPerms": "dashboard-Closed-Area-Gate-Record-Record-Vehicle-Application-Record",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 34,
"showFlag": 1,
"children": null
}
]
}
]
},
{
"extValues": {},
"id": "2030925300149387271",
"menuName": "现场监管",
"menuUrl": "/dashboard/Site/Supervision",
"parentId": "2030925300149387265",
"parentIds": null,
"menuPerms": "dashboard-Site-Supervision",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 6,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387272",
"menuName": "危险作业",
"menuUrl": "/dashboard/Hazardous/Work",
"parentId": "2030925300149387265",
"parentIds": null,
"menuPerms": "dashboard-Hazardous-Work",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 7,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387273",
"menuName": "隐患治理",
"menuUrl": "/dashboard/Hazard/Management",
"parentId": "2030925300149387265",
"parentIds": null,
"menuPerms": "dashboard-Hazard-Management",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 8,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030935458707537921",
"menuName": "入港培训",
"menuUrl": "/dashboard/Study/Training",
"parentId": "2030925300149387265",
"parentIds": null,
"menuPerms": "dashboard-Study-Training",
"menuType": 1,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 11,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387300",
"menuName": "首页扫码",
"menuUrl": "/dashboard/scan",
"parentId": "2030925300149387265",
"parentIds": null,
"menuPerms": "dashboard-scan",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 35,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387301",
"menuName": "首页滚动通知",
"menuUrl": "/dashboard/roll-notice",
"parentId": "2030925300149387265",
"parentIds": null,
"menuPerms": "dashboard-roll-notice",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 36,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387302",
"menuName": "首页待办梳理",
"menuUrl": "/dashboard/todo-sort",
"parentId": "2030925300149387265",
"parentIds": null,
"menuPerms": "dashboard-todo-sort",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 37,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387303",
"menuName": "首页待办事项",
"menuUrl": "/dashboard/todo-list",
"parentId": "2030925300149387265",
"parentIds": null,
"menuPerms": "dashboard-todo-list",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 38,
"showFlag": 1,
"children": null
}
]
},
{
"extValues": {},
"id": "2030925300149387266",
"menuName": "通知",
"menuUrl": "/notice",
"parentId": "0",
"parentIds": null,
"menuPerms": "notice",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 1,
"showFlag": 1,
"children": [
{
"extValues": {},
"id": "2030925300149387274",
"menuName": "公告通知",
"menuUrl": "/notice/Announcement/Notice",
"parentId": "2030925300149387266",
"parentIds": null,
"menuPerms": "notice-Announcement-Notice",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 9,
"showFlag": 1,
"children": null
}
]
},
{
"extValues": {},
"id": "2030925300149387267",
"menuName": "我的",
"menuUrl": "/my-center",
"parentId": "0",
"parentIds": null,
"menuPerms": "my-center",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 2,
"showFlag": 1,
"children": [
{
"extValues": {},
"id": "2030925300149387275",
"menuName": "我的信息",
"menuUrl": "/my-center/My/Information",
"parentId": "2030925300149387267",
"parentIds": null,
"menuPerms": "my-center-My-Information",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 10,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387276",
"menuName": "扫码入职",
"menuUrl": "/my-center/Scan/Code/Onboarding",
"parentId": "2030925300149387267",
"parentIds": null,
"menuPerms": "my-center-Scan-Code-Onboarding",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 11,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387277",
"menuName": "人脸认证",
"menuUrl": "/my-center/Face/Authentication",
"parentId": "2030925300149387267",
"parentIds": null,
"menuPerms": "my-center-Face-Authentication",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 12,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387278",
"menuName": "证书信息",
"menuUrl": "/my-center/Certificate/Information",
"parentId": "2030925300149387267",
"parentIds": null,
"menuPerms": "my-center-Certificate-Information",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 13,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387279",
"menuName": "问题反馈",
"menuUrl": "/my-center/Feedback",
"parentId": "2030925300149387267",
"parentIds": null,
"menuPerms": "my-center-Feedback",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 14,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387280",
"menuName": "版本更新",
"menuUrl": "/my-center/Version/Update",
"parentId": "2030925300149387267",
"parentIds": null,
"menuPerms": "my-center-Version-Update",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 15,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387281",
"menuName": "关于我们",
"menuUrl": "/my-center/About/Us",
"parentId": "2030925300149387267",
"parentIds": null,
"menuPerms": "my-center-About-Us",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 16,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387282",
"menuName": "切换账号",
"menuUrl": "/my-center/Switch/Account",
"parentId": "2030925300149387267",
"parentIds": null,
"menuPerms": "my-center-Switch-Account",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 17,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387283",
"menuName": "修改密码",
"menuUrl": "/my-center/Change/Password",
"parentId": "2030925300149387267",
"parentIds": null,
"menuPerms": "my-center-Change-Password",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 18,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387284",
"menuName": "用户注销",
"menuUrl": "/my-center/User/Logout",
"parentId": "2030925300149387267",
"parentIds": null,
"menuPerms": "my-center-User-Logout",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 19,
"showFlag": 1,
"children": null
},
{
"extValues": {},
"id": "2030925300149387285",
"menuName": "退出登录",
"menuUrl": "/my-center/Logout",
"parentId": "2030925300149387267",
"parentIds": null,
"menuPerms": "my-center-Logout",
"menuType": 2,
"menuAttribution": "QINGANG_RELATED_PARTIES",
"sort": 20,
"showFlag": 1,
"children": null
}
]
}
],
"notEmpty": true,
"empty": false
}

View File

@ -80,7 +80,7 @@ PODS:
- Flutter
- permission_handler_apple (9.3.0):
- Flutter
- photo_manager (3.9.0):
- photo_manager (3.8.0):
- Flutter
- FlutterMacOS
- SDWebImage (5.21.1):
@ -216,7 +216,7 @@ SPEC CHECKSUMS:
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
pdfx: 77f4dddc48361fbb01486fa2bdee4532cbb97ef3
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
photo_manager: 25fd77df14f4f0ba5ef99e2c61814dde77e2bceb
photo_manager: 343d78032bf7ebe944d2ab9702204dc2eda07338
SDWebImage: f29024626962457f3470184232766516dee8dfea
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4

View File

@ -498,17 +498,17 @@
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 8AKCJ9LW7D;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "秦港相关方";
INFOPLIST_KEY_CFBundleDisplayName = "秦港安全";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.2.3;
PRODUCT_BUNDLE_IDENTIFIER = com.qysz.qgxgf;
PRODUCT_BUNDLE_IDENTIFIER = uni.UNI85F7A17;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "qgxgf-dev";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "qa-zsaq";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
@ -525,7 +525,7 @@
DEVELOPMENT_TEAM = 8AKCJ9LW7D;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.qysz.qgxgf.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.company.myapp2.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -544,7 +544,7 @@
DEVELOPMENT_TEAM = 8AKCJ9LW7D;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.qysz.qgxgf.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.company.myapp2.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@ -561,7 +561,7 @@
DEVELOPMENT_TEAM = 8AKCJ9LW7D;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.qysz.qgxgf.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.company.myapp2.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@ -694,17 +694,17 @@
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 8AKCJ9LW7D;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "秦港相关方";
INFOPLIST_KEY_CFBundleDisplayName = "秦港安全";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.2.3;
PRODUCT_BUNDLE_IDENTIFIER = com.qysz.qgxgf;
PRODUCT_BUNDLE_IDENTIFIER = uni.UNI85F7A17;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "qgxgf-dev";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "qa-zsaq";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@ -720,24 +720,24 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Qinhuangdao Zhuoyun Technology Co., Ltd (8AKCJ9LW7D)";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 62;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 8AKCJ9LW7D;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "秦港相关方";
INFOPLIST_KEY_CFBundleDisplayName = "秦港安全";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.2.3;
PRODUCT_BUNDLE_IDENTIFIER = com.qysz.qgxgf;
PRODUCT_BUNDLE_IDENTIFIER = uni.UNI85F7A17;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "qgxgf-des";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "qa-zsaq";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";

View File

@ -5,7 +5,7 @@
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDisplayName</key>
<string>秦港相关方</string>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@ -13,7 +13,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>秦港相关方</string>
<string>秦港双控</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
@ -28,6 +28,8 @@
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NFCReaderUsageDescription</key>
<string>需要NFC权限来读取和写入标签</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>

View File

@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
<dict>
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>TAG</string>
</array>
</dict>
</plist>

View File

@ -2,107 +2,61 @@
import 'dart:convert';
class RouteModel {
//
final String id;
final String menuName; // title
final String menuUrl; // path
final String parentId;
final String parentIds;
final String menuPerms;
final int menuType; // 1/2 ...
final String menuAttribution;
final int sort;
final int showFlag; // 1 0
final Map<String, dynamic> extValues;
final String target;
final List<RouteModel> children;
final bool hasMenu;
final String parentId;
final String routeId;
final String component;
final String path;
final String title;
final String parentIds;
final String meta;
final String routeOrder;
RouteModel({
required this.id,
required this.menuName,
required this.menuUrl,
required this.parentId,
required this.parentIds,
required this.menuPerms,
required this.menuType,
required this.menuAttribution,
required this.sort,
required this.showFlag,
required this.extValues,
required this.target,
required this.children,
required this.hasMenu,
required this.parentId,
required this.routeId,
required this.component,
required this.title,
required this.path,
required this.parentIds,
required this.meta,
required this.routeOrder,
});
factory RouteModel.fromJson(Map<String, dynamic> json) {
//
String _s(dynamic v) => v == null ? '' : v.toString();
int _i(dynamic v) {
if (v == null) return 0;
if (v is int) return v;
return int.tryParse(v.toString()) ?? 0;
}
final rawChildren = json['children'];
final children = <RouteModel>[];
if (rawChildren is List) {
for (final c in rawChildren) {
if (c is Map<String, dynamic>) {
children.add(RouteModel.fromJson(c));
} else if (c is Map) {
children.add(RouteModel.fromJson(Map<String, dynamic>.from(c)));
}
}
}
// extValues
Map<String, dynamic> ext = {};
if (json['extValues'] is Map) {
ext = Map<String, dynamic>.from(json['extValues']);
}
return RouteModel(
id: _s(json['id']),
menuName: _s(json['menuName']),
menuUrl: _s(json['menuUrl']),
parentId: _s(json['parentId']),
parentIds: _s(json['parentIds']),
menuPerms: _s(json['menuPerms']),
menuType: _i(json['menuType']),
menuAttribution: _s(json['menuAttribution']),
sort: _i(json['sort']),
showFlag: _i(json['showFlag']),
extValues: ext,
children: children,
target: json['target'] ?? '',
children: (json['children'] as List<dynamic>? ?? [])
.map((child) => RouteModel.fromJson(child))
.toList(),
hasMenu: json['hasMenu'] ?? false,
parentId: json['parent_ID'] ?? '',
routeId: json['route_ID'] ?? '',
component: json['component'] ?? '',
parentIds: json['parent_IDS'] ?? '',
meta: json['meta'] ?? '',
path: json['path'] ?? '',
title: json['path'] ?? '',
routeOrder: json['route_ORDER'] ?? '0',
);
}
Map<String, dynamic> toJson() => {
'id': id,
'menuName': menuName,
'menuUrl': menuUrl,
'parentId': parentId,
'parentIds': parentIds,
'menuPerms': menuPerms,
'menuType': menuType,
'menuAttribution': menuAttribution,
'sort': sort,
'showFlag': showFlag,
'extValues': extValues,
'children': children.map((c) => c.toJson()).toList(),
};
// // metatitle
// String get title {
// if (meta.isEmpty) return '';
// try {
// final metaMap = jsonDecode(meta) as Map<String, dynamic>;
// return metaMap['title'] ?? '';
// } catch (e) {
// return '';
// }
// }
///
bool get visible => showFlag == 1;
/// menuType /
bool get isMenu => menuType == 2;
///
//
bool get isLeaf => children.isEmpty;
/// menuName extValues title 使
String get title {
if (menuName.isNotEmpty) return menuName;
if (extValues.containsKey('title')) return extValues['title']?.toString() ?? '';
return '';
}
}

View File

@ -1,87 +1,34 @@
// route_service.dart
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:qhd_prevention/common/route_model.dart';
import 'package:qhd_prevention/tools/tools.dart';
class RouteService extends ChangeNotifier {
///
class RouteService {
static final RouteService _instance = RouteService._internal();
factory RouteService() => _instance;
RouteService._internal();
//
//
List<RouteModel> _allRoutes = [];
/// routes
List<RouteModel> get allRoutes => _allRoutes;
// Tabchildren
List<RouteModel> get mainTabs => _allRoutes.isNotEmpty
? _allRoutes.first.children
: [];
/// null
void initializeRoutes(List<dynamic>? routeList) {
_allRoutes = [];
if (routeList == null) return;
for (final item in routeList) {
try {
if (item is Map<String, dynamic>) {
_allRoutes.add(RouteModel.fromJson(item));
} else if (item is Map) {
_allRoutes.add(RouteModel.fromJson(Map<String, dynamic>.from(item)));
}
} catch (e) {
debugPrint('RouteService: parse route item failed: $e');
}
}
// sort
try {
_allRoutes.sort((a, b) => a.sort.compareTo(b.sort));
for (final r in _allRoutes) {
_sortRecursive(r);
}
} catch (_) {}
notifyListeners();
//
void initializeRoutes(List<dynamic> routeList) {
_allRoutes = routeList.map((route) => RouteModel.fromJson(route)).toList();
}
void _sortRecursive(RouteModel node) {
try {
node.children.sort((a, b) => a.sort.compareTo(b.sort));
for (final c in node.children) {
_sortRecursive(c);
}
} catch (_) {}
}
/// parentId == '0' parentId Tab visible
List<RouteModel> get mainTabs {
final tabs = _allRoutes.where((m) {
final isTop = m.parentId == '0' || m.parentId.isEmpty;
return isTop && m.visible; //
}).toList();
try {
tabs.sort((a, b) => a.sort.compareTo(b.sort));
} catch (_) {}
return tabs;
}
// menuUrl
//
RouteModel? findRouteByPath(String path) {
if (path.isEmpty) return null;
final needle = path.trim();
for (final route in _allRoutes) {
final found = _findRouteRecursive(route, needle);
final found = _findRouteRecursive(route, path);
if (found != null) return found;
}
return null;
}
RouteModel? _findRouteRecursive(RouteModel route, String path) {
// null
if (!route.visible) return null;
final routeUrl = route.menuUrl.trim();
if (routeUrl == path) return route;
if (route.path == path) return route;
for (final child in route.children) {
final found = _findRouteRecursive(child, path);
if (found != null) return found;
@ -89,178 +36,23 @@ class RouteService extends ChangeNotifier {
return null;
}
// Tabvisible == true
// TabhasMenutrue
List<RouteModel> getRoutesForTab(RouteModel tab) {
final routes = <RouteModel>[];
_collectVisibleLeafRoutes(tab, routes);
_collectLeafRoutes(tab, routes);
return routes;
}
/// children
void _collectVisibleLeafRoutes(RouteModel route, List<RouteModel> collector) {
if (!route.visible) return; //
if (route.isLeaf) {
void _collectLeafRoutes(RouteModel route, List<RouteModel> collector) {
if (route.hasMenu) {
collector.add(route);
return;
}
for (final child in route.children) {
_collectVisibleLeafRoutes(child, collector);
}
}
// --------------------- ---------------------
/// menuPerms == perm
///
bool hasPerm(String perm) {
if (perm.isEmpty) return false;
final needle = perm.trim();
bool found = false;
void visit(RouteModel m) {
if (found) return;
//
if (!m.visible) return;
final mp = (m.menuPerms ?? '').trim();
if (mp.isNotEmpty && mp == needle) {
found = true;
return;
}
for (final c in m.children) {
visit(c);
if (found) return;
}
}
for (final top in _allRoutes) {
visit(top);
if (found) break;
}
return found;
}
bool hasAnyPerms(List<String> perms) {
for (final p in perms) {
if (hasPerm(p)) return true;
}
return false;
}
Map<String, bool> permsMap(List<String> perms) {
final Map<String, bool> map = {};
for (final p in perms) {
map[p] = hasPerm(p);
}
return map;
}
/// menuPerms RouteModel
///
RouteModel? findRouteByPerm(String perm) {
if (perm.isEmpty) return null;
final needle = perm.trim();
RouteModel? result;
void visit(RouteModel m) {
// printLongString(json.encode(m.toJson()));
if (result != null) return;
if (!m.visible) return; //
final mp = (m.menuPerms ?? '').trim();
if (mp.isNotEmpty && mp == needle) {
result = m;
return;
}
for (final c in m.children) {
visit(c);
if (result != null) return;
}
}
for (final top in _allRoutes) {
visit(top);
if (result != null) break;
}
return result;
}
/// menuPerms
List<String> collectAllPerms() {
final List<String> perms = [];
void visit(RouteModel m) {
if (!m.visible) return; //
final mp = (m.menuPerms ?? '').trim();
if (mp.isNotEmpty) perms.add(mp);
for (final c in m.children) visit(c);
}
for (final top in _allRoutes) visit(top);
return perms;
}
///
static Future<String> getMenuPath(parentPerm,targetPerm) async {
try {
final routeService = RouteService();
// ''children
if (targetPerm.isEmpty) {
final route = routeService.findRouteByPerm(parentPerm);
if (route != null) {
// menuUrl
final childUrl = findFirstVisibleChildUrl(route);
if (childUrl.isNotEmpty) return childUrl;
return '';
if (!route.isLeaf) {
for (final child in route.children) {
_collectLeafRoutes(child, collector);
}
}
//branchCompany-plan-execute-inspection-records
RouteModel? parent = routeService.findRouteByPerm(parentPerm);
if (parent != null) {
// parent targetPerm
final RouteModel? foundInParent = _findRouteInSubtreeByPerm(parent, targetPerm);
if (foundInParent != null && foundInParent.menuUrl.trim().isNotEmpty) {
return foundInParent.menuUrl.trim();
}
}
// ->
return '';
} catch (e, st) {
debugPrint('_getMenuPath error: $e\n$st');
return '';
}
}
/// menuPerm
static RouteModel? _findRouteInSubtreeByPerm(RouteModel node, String perm) {
if (node.menuPerms.trim() == perm && node.visible) return node;
for (final c in node.children) {
final res = _findRouteInSubtreeByPerm(c, perm);
if (res != null) return res;
}
return null;
}
/// menuPerm
RouteModel? _findRouteInAllByPerm(List<RouteModel> roots, String perm) {
for (final r in roots) {
final res = _findRouteInSubtreeByPerm(r, perm);
if (res != null) return res;
}
return null;
}
/// node visible menuUrl
///
static String findFirstVisibleChildUrl(RouteModel node) {
final children = node.children;
if (children == null || children.isEmpty) return '';
for (final c in children) {
// menuUrl
if ((c.showFlag == 1) && (c.menuUrl ?? '').isNotEmpty) {
return c.menuUrl;
}
// return '';
}
return '';
}
}

View File

@ -104,9 +104,6 @@ class MediaPickerRow extends StatefulWidget {
/// 4/ 1
final int crossAxisCount;
/// 1 2 3
final int selectPictureType;
const MediaPickerRow({
Key? key,
this.maxCount = 4,
@ -121,7 +118,6 @@ class MediaPickerRow extends StatefulWidget {
this.isCamera = false,
this.followInitialUpdates = false, // false
this.crossAxisCount = 4, // 4
this.selectPictureType = 3,
}) : super(key: key);
@override
@ -267,26 +263,24 @@ class _MediaPickerGridState extends State<MediaPickerRow> {
builder: (_) => SafeArea(
child: Wrap(
children: [
if(widget.selectPictureType==3||widget.selectPictureType==1)
ListTile(
titleAlignment: ListTileTitleAlignment.center,
leading: Icon(widget.mediaType == MediaType.image ? Icons.camera_alt : Icons.videocam),
title: Text(widget.mediaType == MediaType.image ? '拍照' : '拍摄视频'),
onTap: () {
Navigator.of(context).pop();
_pickCamera();
},
),
if(widget.selectPictureType==3||widget.selectPictureType==2)
ListTile(
titleAlignment: ListTileTitleAlignment.center,
leading: Icon(widget.mediaType == MediaType.image ? Icons.photo_library : Icons.video_library),
title: Text(widget.mediaType == MediaType.image ? '从相册选择' : '从相册选择视频'),
onTap: () {
Navigator.of(context).pop();
_pickGallery();
},
),
ListTile(
titleAlignment: ListTileTitleAlignment.center,
leading: Icon(widget.mediaType == MediaType.image ? Icons.camera_alt : Icons.videocam),
title: Text(widget.mediaType == MediaType.image ? '拍照' : '拍摄视频'),
onTap: () {
Navigator.of(context).pop();
_pickCamera();
},
),
ListTile(
titleAlignment: ListTileTitleAlignment.center,
leading: Icon(widget.mediaType == MediaType.image ? Icons.photo_library : Icons.video_library),
title: Text(widget.mediaType == MediaType.image ? '从相册选择' : '从相册选择视频'),
onTap: () {
Navigator.of(context).pop();
_pickGallery();
},
),
ListTile(
titleAlignment: ListTileTitleAlignment.center,
leading: const Icon(Icons.close),
@ -650,8 +644,6 @@ class RepairedPhotoSection extends StatefulWidget {
final bool inlineSingle;
/// inlineSingle true px
final double inlineImageWidth;
/// 1 2 3
final int selectPictureType;
const RepairedPhotoSection({
Key? key,
@ -676,7 +668,6 @@ class RepairedPhotoSection extends StatefulWidget {
this.sectionKey = kAcceptVideoSectionKey,
this.inlineSingle = false,
this.inlineImageWidth = 88.0,
this.selectPictureType = 3,
}) : super(key: key);
@override
@ -811,75 +802,73 @@ class _RepairedPhotoSectionState extends State<RepairedPhotoSection> {
builder: (ctx) => SafeArea(
child: Wrap(
children: [
if(widget.selectPictureType==3||widget.selectPictureType==1)
ListTile(
titleAlignment: ListTileTitleAlignment.center,
leading: Icon(widget.mediaType == MediaType.image ? Icons.camera_alt : Icons.videocam),
title: Text(widget.mediaType == MediaType.image ? '拍照' : '拍摄视频'),
onTap: () async {
Navigator.of(ctx).pop();
// MediaPickerRow camera ImagePicker
final picker = ImagePicker();
try {
if (widget.mediaType == MediaType.image) {
final x = await picker.pickImage(source: ImageSource.camera);
if (x != null) {
setState(() {
_mediaPaths = [x.path];
});
widget.onChanged(_localFilesFromPaths(_mediaPaths));
widget.onMediaAdded?.call(x.path);
}
} else {
final x = await picker.pickVideo(source: ImageSource.camera);
if (x != null) {
// VideoCompress
setState(() {
_mediaPaths = [x.path];
});
widget.onChanged(_localFilesFromPaths(_mediaPaths));
widget.onMediaAdded?.call(x.path);
}
ListTile(
titleAlignment: ListTileTitleAlignment.center,
leading: Icon(widget.mediaType == MediaType.image ? Icons.camera_alt : Icons.videocam),
title: Text(widget.mediaType == MediaType.image ? '拍照' : '拍摄视频'),
onTap: () async {
Navigator.of(ctx).pop();
// MediaPickerRow camera ImagePicker
final picker = ImagePicker();
try {
if (widget.mediaType == MediaType.image) {
final x = await picker.pickImage(source: ImageSource.camera);
if (x != null) {
setState(() {
_mediaPaths = [x.path];
});
widget.onChanged(_localFilesFromPaths(_mediaPaths));
widget.onMediaAdded?.call(x.path);
}
} catch (e) {
debugPrint('camera pick error: $e');
ToastUtil.showNormal(context, '拍摄失败');
}
},
),
if(widget.selectPictureType==3||widget.selectPictureType==2)
ListTile(
titleAlignment: ListTileTitleAlignment.center,
leading: Icon(widget.mediaType == MediaType.image ? Icons.photo_library : Icons.video_library),
title: Text(widget.mediaType == MediaType.image ? '从相册选择' : '从相册选择视频'),
onTap: () async {
Navigator.of(ctx).pop();
// AssetPicker MediaPickerRow
try {
final List<AssetEntity>? assets = await AssetPicker.pickAssets(
context,
pickerConfig: AssetPickerConfig(
requestType: widget.mediaType == MediaType.image ? RequestType.image : RequestType.video,
maxAssets: 1,
gridCount: 4,
),
);
if (assets != null && assets.isNotEmpty) {
final file = await assets.first.file;
if (file != null) {
setState(() {
_mediaPaths = [file.path];
});
widget.onChanged(_localFilesFromPaths(_mediaPaths));
widget.onMediaAdded?.call(file.path);
}
} else {
final x = await picker.pickVideo(source: ImageSource.camera);
if (x != null) {
// VideoCompress
setState(() {
_mediaPaths = [x.path];
});
widget.onChanged(_localFilesFromPaths(_mediaPaths));
widget.onMediaAdded?.call(x.path);
}
} catch (e) {
debugPrint('pick asset error: $e');
ToastUtil.showNormal(context, '选择图片失败');
}
},
),
} catch (e) {
debugPrint('camera pick error: $e');
ToastUtil.showNormal(context, '拍摄失败');
}
},
),
ListTile(
titleAlignment: ListTileTitleAlignment.center,
leading: Icon(widget.mediaType == MediaType.image ? Icons.photo_library : Icons.video_library),
title: Text(widget.mediaType == MediaType.image ? '从相册选择' : '从相册选择视频'),
onTap: () async {
Navigator.of(ctx).pop();
// AssetPicker MediaPickerRow
try {
final List<AssetEntity>? assets = await AssetPicker.pickAssets(
context,
pickerConfig: AssetPickerConfig(
requestType: widget.mediaType == MediaType.image ? RequestType.image : RequestType.video,
maxAssets: 1,
gridCount: 4,
),
);
if (assets != null && assets.isNotEmpty) {
final file = await assets.first.file;
if (file != null) {
setState(() {
_mediaPaths = [file.path];
});
widget.onChanged(_localFilesFromPaths(_mediaPaths));
widget.onMediaAdded?.call(file.path);
}
}
} catch (e) {
debugPrint('pick asset error: $e');
ToastUtil.showNormal(context, '选择图片失败');
}
},
),
ListTile(
titleAlignment: ListTileTitleAlignment.center,
leading: const Icon(Icons.close),
@ -935,8 +924,7 @@ class _RepairedPhotoSectionState extends State<RepairedPhotoSection> {
padding: EdgeInsets.symmetric(horizontal: widget.horizontalPadding),
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: widget.title,
// rightText: widget.isShowNum ? '${_mediaPaths.length}/${widget.maxCount}' : '',
rightText: widget.isShowNum ? '${_getCurrentCount()}/${widget.maxCount}' : '',
rightText: widget.isShowNum ? '${_mediaPaths.length}/${widget.maxCount}' : '',
isRequired: widget.isRequired,
),
),
@ -949,7 +937,6 @@ class _RepairedPhotoSectionState extends State<RepairedPhotoSection> {
initialMediaPaths: _mediaPaths,
onMediaRemovedForIndex: widget.onMediaRemovedForIndex,
isCamera: widget.isCamera,
selectPictureType:widget.selectPictureType,
onChanged: (files) {
final newPaths = files.map((f) => f.path).toList();
setState(() {
@ -1001,17 +988,5 @@ class _RepairedPhotoSectionState extends State<RepairedPhotoSection> {
),
);
}
int _getCurrentCount() {
// followInitialUpdates true使
// false使
if (widget.followInitialUpdates) {
return _mediaPaths.length;
} else {
return widget.initialMediaPaths?.length ?? _mediaPaths.length;
}
}
}

View File

@ -21,7 +21,7 @@ class ApiService {
isProduct
? "https://jpfz.qhdsafety.com/gbsFileTest/"
: "http://192.168.20.240:9787/mnt/"; //
// static final String baseImgPath = "https://skqhdg.porthebei.com:9004/file/uploadFiles2/";
// static final String baseImgPath = "https://skqhdg.porthebei.com:9004/file/";
static const publicKey =

View File

@ -1,17 +0,0 @@
import 'package:dio/dio.dart';
import 'package:qhd_prevention/http/ApiService.dart';
import 'package:qhd_prevention/http/HttpManager.dart';
import 'package:qhd_prevention/services/SessionService.dart';
class AppMenuApi {
static Future<Map<String, dynamic>> getAppMenu() async {
return HttpManager().request(
ApiService.basePath,
'/appmenu/appMenu/appListTree',
method: Method.get,
data: {
'menuAttribution': 'QINGANG_RELATED_PARTIES',
},
);
}
}

View File

@ -169,7 +169,7 @@ class CertificateApi {
static Future<Map<String, dynamic>> getCertificateList(Map data) {
return HttpManager().request(
ApiService.basePath + '/certificate',
'/userCertificate/listPage',
'/userCertificate/list',
method: Method.post,
data: {...data},
);
@ -221,3 +221,17 @@ class CertificateApi {
}
}
//
class TodoApi {
static Future<Map<String, dynamic>> getTodoList(Map data) {
return HttpManager().request(
ApiService.basePath + '/appmenu',
'/todoList/list',
method: Method.post,
data: {
'eqFlag' : 1,
...data
},
);
}
}

View File

@ -57,7 +57,7 @@ class EduApi {
static Future<Map<String, dynamic>> getSignInList(Map data) async {
return HttpManager().request(
'${ApiService.basePath}/edu',
'/app/studentSign/listAllNoGroup',
'/app/studentSign/listAll',
method: Method.post,
data: {
...data,

View File

@ -70,7 +70,6 @@ Future<T?> showModalBottomSheetAfterUnfocus<T>({
void main( ) async {
WidgetsFlutterBinding.ensureInitialized();
StorageService.instance.init();
/**
// 1) SDK SDK
BMFMapSDK.setAgreePrivacy(true);
@ -83,7 +82,7 @@ void main( ) async {
BMFMapSDK.setApiKeyAndCoordType('43G1sKuHV6oRTrdR9VTIGPF9soej7V5a', BMF_COORD_TYPE.BD09LL);
await BMFAndroidVersion.initAndroidVersion(); //
}
*/
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,

View File

@ -13,7 +13,6 @@ import 'package:qhd_prevention/pages/mine/face_ecognition_page.dart';
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/services/SessionService.dart';
import 'package:qhd_prevention/services/scan_service.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/search_bar_widget.dart';
@ -147,7 +146,6 @@ class _StudyClassListPageState extends State<StudyClassListPage> {
await pushPage(SigninInformationListPage(info: item), context);
},
),
if (item['examination'] != 0)
CustomButton(
text: '考试记录',
height: 35,
@ -227,11 +225,7 @@ class _StudyClassListPageState extends State<StudyClassListPage> {
child: Center(child: CircularProgressIndicator()),
);
}
final item = list[index];
if (item['state'] != 1) {
return _buildListItem(item);
}
return SizedBox(height: 0);
return _buildListItem(list[index]);
},
);
}
@ -243,7 +237,68 @@ class _StudyClassListPageState extends State<StudyClassListPage> {
ToastUtil.showNormal(context, '未扫描到二维码');
return;
}
ScanService.scan(context, result);
int type = result['type'] ?? 0;
final data = {
...result,
'phone': SessionService.instance.userData?.phone ?? '',
'type': type,
};
LoadingDialogHelper.show();
//
final response = await EduApi.checkSignIn(data);
LoadingDialogHelper.hide();
if (response['success']) {
//
final filePath = await pushPage(
const FaceRecognitionPage(
studentId: '',
data: {},
mode: FaceMode.study,
),
context,
);
final faceData = response['data'];
if (filePath != null) {
//
try {
LoadingDialogHelper.show();
final response = await EduApi.compareFace({
'type': data['type'],
'studentId': faceData['studentId'],
}, filePath);
final faceResultData = response['data'];
if (response['success']) {
final signData = {
'id': faceResultData['id'] ?? '',
'studentId': faceResultData['studentId'] ?? '',
'type': data['type']?? '',
'classId': faceResultData['classId'] ?? '',
'studentSignId':faceResultData['studentSignId']??''
};
_signUpload(signData, type);
} else {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, response['errMessage'] ?? '验证失败');
}
} catch (e) {
ToastUtil.showNormal(context,'验证失败');
LoadingDialogHelper.hide();
print(e);
}
} else {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, '签到失败');
}
} else {
ToastUtil.showNormal(context, response['errMessage'] ?? '签到失败');
}
}
//

View File

@ -242,9 +242,7 @@ class _StudyTakeExamPageState extends State<StudyTakeExamPage> {
if (res['success']) {
final data = res['data'] as Map<String, dynamic>? ?? {};
final score = data['examScore'] ?? 0;
var passed = data['result'] == 1;
//
bool remain = (data['surplusExamNum'] ?? 0) <= 0;
final passed = data['result'] == 1;
// /
final result = await CustomAlertDialog.showConfirm(
@ -253,7 +251,7 @@ class _StudyTakeExamPageState extends State<StudyTakeExamPage> {
content: passed
? '您的成绩为 $score 分,恭喜您通过本次考试,请继续保持!'
: '您的成绩为 $score 分,很遗憾您没有通过本次考试,请再接再厉!',
cancelText: remain ? '' : '继续考试',
cancelText: passed ? '' : '继续考试',
confirmText: '确定',
);
@ -267,7 +265,7 @@ class _StudyTakeExamPageState extends State<StudyTakeExamPage> {
_resetForRetry();
} else {
//
final msg = res['errMessage'] ?? '提交失败,请重试';
final msg = res['message'] ?? '提交失败,请重试';
ToastUtil.showError(context, msg);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:qhd_prevention/common/route_model.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/customWidget/work_tab_icon_grid.dart';
import 'package:qhd_prevention/http/ApiService.dart';
import 'package:qhd_prevention/customWidget/IconBadgeButton.dart';
@ -9,7 +6,6 @@ import 'package:qhd_prevention/pages/home/unit/unit_join_list_page.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:qhd_prevention/common/route_aware_state.dart';
import 'package:qhd_prevention/common/route_service.dart';
class UnitTabPage extends StatefulWidget {
const UnitTabPage({super.key});
@ -19,166 +15,47 @@ class UnitTabPage extends StatefulWidget {
}
class _UnitTabPageState extends RouteAwareState<UnitTabPage> {
// master
final List<Map<String, dynamic>> _masterButtons = [
late List<Map<String, dynamic>> buttonInfos = [
{
"icon": "assets/images/unit_ico1.png",
"title": "服务单位管理",
"unreadCount": 0,
},
{
}
,{
"icon": "assets/images/unit_ico2.png",
"title": "就职单位管理",
"unreadCount": 0,
},
}
];
// title -> menuPerm
final Map<String, String> _permMapping = {
"服务单位管理": "dashboard-Unit-Management-Managee-Service-Unit-Management",
"就职单位管理": "dashboard-Unit-Management-Employment-Unit",
};
// master
late List<bool> _visible;
@override
void initState() {
super.initState();
//
_visible = List<bool>.filled(_masterButtons.length, true);
//
RouteService().addListener(_onRouteUpdated);
//
WidgetsBinding.instance.addPostFrameCallback((_) => _updateVisibilityFromRoute());
}
@override
void dispose() {
try {
RouteService().removeListener(_onRouteUpdated);
} catch (_) {}
super.dispose();
}
void _onRouteUpdated() {
//
_updateVisibilityFromRoute();
}
void _updateVisibilityFromRoute() {
final routeService = RouteService();
// routesLoaded: mainTabs
final bool routesLoaded = routeService.mainTabs.isNotEmpty;
final List<bool> next = List<bool>.filled(_masterButtons.length, false);
for (int i = 0; i < _masterButtons.length; i++) {
final title = _masterButtons[i]['title'] as String;
final perm = _permMapping[title] ?? '';
if (!routesLoaded) {
//
next[i] = true;
continue;
}
if (perm.isEmpty) {
//
next[i] = false;
continue;
}
// 使 RouteService.findRouteByPerm visible
final RouteModel? node = routeService.findRouteByPerm(perm);
if (node != null) {
// showFlag == 1
next[i] = (node.showFlag == 1) || (node.visible);
} else {
// menuPerm使 perms
// menuPerm findRouteByPerm
RouteModel? fallback;
for (final top in routeService.allRoutes) {
fallback = _findRouteRecursiveByPerm(top, perm);
if (fallback != null) break;
}
next[i] = fallback != null ? ((fallback.showFlag == 1) || (fallback.visible)) : false;
}
}
// setState
if (!listEquals(next, _visible)) {
setState(() {
_visible = next;
});
}
}
/// node menuPerms targetPerm
/// RouteService.findRouteByPerm fallback
RouteModel? _findRouteRecursiveByPerm(RouteModel node, String targetPerm) {
if ((node.menuPerms ?? '') == targetPerm) return node;
for (final c in node.children) {
final res = _findRouteRecursiveByPerm(c, targetPerm);
if (res != null) return res;
}
return null;
}
//
@override
Future<void> onVisible() async {
await _getData();
_getData();
}
Future<void> _getData() async {
// TODO: / setState _masterButtons[*]['unreadCount']
// await Future.delayed(Duration(milliseconds: 100));
}
void _handleIconTap(int index) async {
final title = _masterButtons[index]['title'] as String;
switch (title) {
case '服务单位管理':
ToastUtil.showNormal(context, '您还没有参与项目');
switch (index) {
case 0:
break;
case '就职单位管理':
case 1:
pushPage(UnitJoinListPage(), context);
break;
default:
break;
}
//
await _getData();
_getData();
}
@override
Widget build(BuildContext context) {
final double screenW = MediaQuery.of(context).size.width;
final double bannerHeight = 618 / 1125 * screenW;
// icon 4
final visibleButtons = <Map<String, dynamic>>[];
for (int i = 0; i < _masterButtons.length; i++) {
if (i < _visible.length && _visible[i]) visibleButtons.add(_masterButtons[i]);
}
final int visibleCount = visibleButtons.length;
final int perRow = 4;
final int rows = visibleCount == 0 ? 0 : ((visibleCount + perRow - 1) ~/ perRow);
//
const double verticalPadding = 30.0;
const double perRowHeight = 110.0; // + +
const double rowSpacing = 20.0;
final double iconSectionHeight = visibleCount == 0 ? 150.0 : (verticalPadding + rows * perRowHeight + (rows - 1) * rowSpacing);
const double iconOverlapBanner = 30.0;
double bannerHeight = 618/1125 * MediaQuery.of(context).size.width;
const double iconSectionHeight = 150.0;
const double iconOverlapBanner = 30.0; // banner
return PopScope(
canPop: true,
child: Scaffold(
@ -208,7 +85,7 @@ class _UnitTabPageState extends RouteAwareState<UnitTabPage> {
right: 10,
top: bannerHeight - iconOverlapBanner,
height: iconSectionHeight,
child: _buildIconSection(context, visibleButtons, rows),
child: _buildIconSection(context),
),
],
),
@ -217,12 +94,13 @@ class _UnitTabPageState extends RouteAwareState<UnitTabPage> {
),
),
);
}
// Banner
}
// Banner
Widget _buildBannerSection(double height) {
return Stack(
children: [
//
Image.asset(
"assets/images/unit_banner.jpg",
width: MediaQuery.of(context).size.width,
@ -232,80 +110,54 @@ class _UnitTabPageState extends RouteAwareState<UnitTabPage> {
],
);
}
// visibleButtons icon
Widget _buildIconSection(BuildContext context, List<Map<String, dynamic>> visibleButtons, int rows) {
if (visibleButtons.isEmpty) {
if (RouteService().mainTabs.isNotEmpty) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 5),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 6, offset: Offset(0, 2))],
),
child: const Center(child: Text('暂无权限访问的功能')),
);
} else {
return Container(
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 5),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 6, offset: Offset(0, 2))],
),
child: const Center(child: SizedBox()),
);
}
}
// 4
final List<Widget> rowsWidgets = [];
final int perRow = 4;
for (int r = 0; r < rows; r++) {
final start = r * perRow;
final end = (start + perRow) > visibleButtons.length ? visibleButtons.length : (start + perRow);
final rowItems = visibleButtons.sublist(start, end);
rowsWidgets.add(
Row(
children: List.generate(perRow, (i) {
final idx = start + i;
if (idx < visibleButtons.length) {
final btn = visibleButtons[idx];
// master onTap
final masterIndex = _masterButtons.indexWhere((m) => m['title'] == btn['title']);
return Expanded(
child: Center(child: _buildIconButton(btn, masterIndex)),
);
} else {
return const Expanded(child: SizedBox.shrink());
}
}),
),
);
if (r != rows - 1) rowsWidgets.add(const SizedBox(height: 20));
}
Widget _buildIconSection(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 5),
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 5),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 6, offset: Offset(0, 2))],
boxShadow: const [
BoxShadow(
color: Colors.black12,
blurRadius: 6,
offset: Offset(0, 2),
),
],
),
child: Column(
children: [
_buildIconRow(startIndex: 0),
],
),
child: Column(children: rowsWidgets),
);
}
Widget _buildIconRow({required int startIndex}) {
final List<Widget> cells = List.generate(4, (i) {
final int idx = startIndex + i;
if (idx < buttonInfos.length) {
return Expanded(
child: Center(child: _buildIconButton(buttonInfos[idx], idx, context)),
);
} else {
return const Expanded(
child: SizedBox.shrink(),
);
}
});
Widget _buildIconButton(Map<String, dynamic> info, int masterIndex) {
final unread = (info['unreadCount'] ?? 0) is int ? info['unreadCount'] as int : int.tryParse('${info['unreadCount']}') ?? 0;
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: cells,
);
}
Widget _buildIconButton(Map<String, dynamic> info, int index, BuildContext context) {
return IconBadgeButton(
iconPath: info['icon'] ?? '',
title: info['title'] ?? '',
unreadCount: unread,
onTap: () => _handleIconTap(masterIndex),
unreadCount: (info['unreadCount'] ?? 0) is int ? info['unreadCount'] as int : int.tryParse('${info['unreadCount']}') ?? 0,
onTap: () => _handleIconTap(index),
);
}
}

View File

@ -1,22 +1,15 @@
// lib/pages/new/main_page.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:qhd_prevention/common/route_service.dart';
import 'package:qhd_prevention/http/modules/appmenu_api.dart';
import 'package:qhd_prevention/pages/badge_manager.dart';
import 'package:qhd_prevention/pages/home/home_page.dart';
import 'package:qhd_prevention/pages/mine/mine_page.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/pages/notif/notif_page.dart';
import 'package:qhd_prevention/services/heartbeat_service.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'mine/mine_page.dart';
/// tab
class CurrentTabNotifier extends InheritedWidget {
final int currentIndex;
const CurrentTabNotifier({
required this.currentIndex,
required Widget child,
@ -45,14 +38,10 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
int _currentIndex = 0;
final GlobalKey<HomePageState> _homeKey = GlobalKey<HomePageState>();
final GlobalKey<NotifPageState> _notifKey = GlobalKey<NotifPageState>();
// final GlobalKey<ApplicationPageTwoState> _appKey = GlobalKey<ApplicationPageTwoState>();
final GlobalKey<MinePageState> _mineKey = GlobalKey<MinePageState>();
// _tabVisibility
late final List<Widget> _pages;
// Tab _pages
// [, , ]
late List<bool> _tabVisibility;
late List<Widget> _pages;
late List<bool> _tabVisibility; // Tab
// BadgeManager
late final BadgeManager _badgeManager;
@ -60,158 +49,53 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_badgeManager = BadgeManager();
_badgeManager.addListener(_onBadgeChanged);
// BadgeManager
if (widget.isChooseFirm) {
_badgeManager.initAllModules();
}
_badgeManager = BadgeManager();
_badgeManager.initAllModules();
// BadgeManager
_badgeManager.addListener(_onBadgeChanged);
// ****
//
WidgetsBinding.instance.addObserver(this);
// Tab
_tabVisibility = [true, true, true];
_pages = <Widget>[
HomePage(key: _homeKey, isChooseFirm: widget.isChooseFirm),
NotifPage(key: _notifKey),
MinePage(key: _mineKey, isChooseFirm: widget.isChooseFirm),
];
// tab
_tabVisibility = [false, false, false];
// RouteService /
RouteService().addListener(_onRoutesUpdated);
// 退 assets
_getRoute();
}
/// 退 assets/route/routes.txt
Future<void> _getRoute() async {
try {
Map? route;
//
// try {
// LoadingDialogHelper.show(message: '加载中...');
// final res = await AppMenuApi.getAppMenu();
// if (res != null && res['success'] == true && res['data'] is List) {
// route = res;
// } else {
// debugPrint('AppMenuApi.getAppMenu returned no data or failed; fallback to local assets.');
// }
// } catch (e) {
// debugPrint('AppMenuApi.getAppMenu error: $e -> fallback to local assets.');
// }
//
try {
final routeString = await loadFromAssets();
route = jsonDecode(routeString) as Map<String, dynamic>;
} catch (e) {
debugPrint('loadFromAssets error: $e');
}
if (route != null && route['data'] is List) {
final data = route['data'] as List<dynamic>;
RouteService().initializeRoutes(data);
// initializeRoutes notifyListeners -> _onRoutesUpdated
} else {
debugPrint('No valid route data to initialize RouteService.');
}
} catch (e) {
debugPrint('获取路由配置失败: $e');
} finally {
LoadingDialogHelper.hide();
}
}
Future<String> loadFromAssets() async {
return await rootBundle.loadString('assets/route/routes.txt');
}
void _onRoutesUpdated() {
//
_updateTabVisibilityFromRoutes();
}
/// RouteService _tabVisibility
///
/// - menuPerms == 'dashboard'
/// - menuPerms == 'notice'
/// - menuPerms == 'my-center'
void _updateTabVisibilityFromRoutes() {
final routeService = RouteService();
// 使 mainTabs _tabVisibility
final mainTabs = routeService.mainTabs;
if (mainTabs.isEmpty) {
return;
}
bool homeVisible = false;
bool notifVisible = false;
bool mineVisible = false;
for (final m in mainTabs) {
final perms = (m.menuPerms ?? '').toString();
if (!homeVisible && perms == 'dashboard' && m.visible) {
homeVisible = true;
}
if (!notifVisible && perms == 'notice'&& m.visible) {
notifVisible = true;
}
if (!mineVisible && perms == 'my-center'&& m.visible) {
mineVisible = true;
}
if (homeVisible && notifVisible && mineVisible) break;
}
//
setState(() {
_tabVisibility = [homeVisible, widget.isChooseFirm ? notifVisible : false, mineVisible];
// tab tab tab 0
if (!_isIndexVisible(_currentIndex)) {
final first = _firstVisibleIndexOrDefault(_currentIndex);
_currentIndex = first;
}
});
}
// tab fallback0
int _firstVisibleIndexOrDefault([int fallback = 0]) {
for (int i = 0; i < _tabVisibility.length; i++) {
if (_tabVisibility[i]) return i;
}
return fallback;
}
bool _isIndexVisible(int index) {
if (index < 0 || index >= _tabVisibility.length) return false;
return _tabVisibility[index];
//
HeartbeatService().start();
}
@override
void dispose() {
//
_badgeManager.removeListener(_onBadgeChanged);
RouteService().removeListener(_onRoutesUpdated);
//
WidgetsBinding.instance.removeObserver(this);
//
HeartbeatService().stop();
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
switch (state) {
case AppLifecycleState.resumed:
//
HeartbeatService().resume();
break;
case AppLifecycleState.paused:
case AppLifecycleState.inactive:
case AppLifecycleState.detached:
case AppLifecycleState.hidden:
//
HeartbeatService().pause();
break;
}
@ -250,53 +134,33 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
);
}
// ( 0..n) (visiblePages )
// originalIndex 0
int _originalToVisibleIndex(int originalIndex, List<bool> visibility) {
int visibleIndex = 0;
for (int i = 0; i < visibility.length; i++) {
if (!visibility[i]) continue;
if (i == originalIndex) return visibleIndex;
visibleIndex++;
}
// originalIndex -> 0
return visibility.contains(true) ? 0 : 0;
}
// BottomNavigationBar onTap
// visibleIndex 0
int _visibleToOriginalIndex(int visibleIndex, List<bool> visibility) {
int count = 0;
for (int i = 0; i < visibility.length; i++) {
if (!visibility[i]) continue;
if (count == visibleIndex) return i;
count++;
}
// 0
for (int i = 0; i < visibility.length; i++) {
if (visibility[i]) return i;
}
return 0;
}
@override
Widget build(BuildContext context) {
// 使 _badgeManager BadgeManager()
final bm = _badgeManager;
// _tabVisibility
//
final List<BottomNavigationBarItem> visibleItems = [];
final List<Widget> visiblePages = [];
for (int i = 0; i < _pages.length; i++) {
for (int i = 0; i < _tabVisibility.length; i++) {
if (_tabVisibility[i]) {
switch (i) {
case 0:
visibleItems.add(BottomNavigationBarItem(
icon: Image.asset('assets/tabbar/basics.png', width: 24, height: 24),
activeIcon: Image.asset('assets/tabbar/basics_cur.png', width: 24, height: 24),
label: '首页',
));
visibleItems.add(
BottomNavigationBarItem(
icon: Image.asset(
'assets/tabbar/basics.png',
width: 24,
height: 24,
),
activeIcon: Image.asset(
'assets/tabbar/basics_cur.png',
width: 24,
height: 24,
),
label: '首页',
),
);
visiblePages.add(_pages[i]);
break;
case 1:
@ -314,105 +178,83 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
visiblePages.add(_pages[i]);
break;
case 2:
visibleItems.add(BottomNavigationBarItem(
icon: Image.asset('assets/tabbar/my.png', width: 24, height: 24),
activeIcon: Image.asset('assets/tabbar/my_cur.png', width: 24, height: 24),
label: '我的',
));
visibleItems.add(
BottomNavigationBarItem(
icon: Image.asset(
'assets/tabbar/my.png',
width: 24,
height: 24,
),
activeIcon: Image.asset(
'assets/tabbar/my_cur.png',
width: 24,
height: 24,
),
label: '我的',
),
);
visiblePages.add(_pages[i]);
break;
}
}
}
// body
final bool hasVisiblePages = visiblePages.isNotEmpty;
// Tab IndexedStack/BottomNavigationBar
final visibleCurrentIndex = _originalToVisibleIndex(_currentIndex, _tabVisibility);
// ---------- visibleItems ----------
Widget? bottomBarWidget;
if (visibleItems.length >= 2) {
// 使 BottomNavigationBar 2 item
bottomBarWidget = BottomNavigationBar(
currentIndex: visibleCurrentIndex,
type: BottomNavigationBarType.fixed,
selectedItemColor: Colors.blue,
unselectedItemColor: Colors.grey,
onTap: (visibleIndex) {
final originalIndex = _visibleToOriginalIndex(visibleIndex, _tabVisibility);
setState(() => _currentIndex = originalIndex);
},
items: visibleItems,
);
} else if (visibleItems.length == 1) {
// tab BottomNavigationBar
final single = visibleItems[0];
final singleVisibleOriginalIndex = _visibleToOriginalIndex(0, _tabVisibility);
final isSelected = _currentIndex == singleVisibleOriginalIndex;
// icon
final Widget iconWidget = isSelected && single.activeIcon != null ? single.activeIcon! : single.icon;
bottomBarWidget = Material(
elevation: 8,
child: InkWell(
onTap: () {
setState(() {
_currentIndex = singleVisibleOriginalIndex;
});
},
child: Container(
height: kBottomNavigationBarHeight,
color: Colors.white,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
//
SizedBox(
width: 28,
height: 28,
child: Center(child: iconWidget),
),
const SizedBox(height: 4),
//
Text(
single.label ?? '',
style: TextStyle(
color: isSelected ? Colors.blue : Colors.grey,
fontSize: 12,
),
),
],
),
),
),
),
);
} else {
// ->
bottomBarWidget = null;
// Tab
int getVisibleIndex(int originalIndex) {
int visibleIndex = 0;
for (int i = 0; i <= originalIndex; i++) {
if (_tabVisibility[i]) {
if (i == originalIndex) return visibleIndex;
visibleIndex++;
}
}
return 0; // Tab
}
final visibleCurrentIndex = getVisibleIndex(_currentIndex);
return CurrentTabNotifier(
currentIndex: _currentIndex,
child: Scaffold(
appBar: null,
body: hasVisiblePages
? IndexedStack(
index: visibleCurrentIndex,
children: visiblePages,
)
: const SizedBox.shrink(),
bottomNavigationBar: bottomBarWidget,
body: IndexedStack(index: visibleCurrentIndex, children: visiblePages),
bottomNavigationBar:
visibleItems.length >= 2
? BottomNavigationBar(
currentIndex: visibleCurrentIndex,
type: BottomNavigationBarType.fixed,
selectedItemColor: Colors.blue,
unselectedItemColor: Colors.grey,
onTap: (visibleIndex) {
int originalIndex = 0;
int count = 0;
for (int i = 0; i < _tabVisibility.length; i++) {
if (_tabVisibility[i]) {
if (count == visibleIndex) {
originalIndex = i;
break;
}
count++;
}
}
setState(() => _currentIndex = originalIndex);
},
items: visibleItems,
)
: null, // Tab
),
);
}
void _onBadgeChanged() {
//
if (mounted) setState(() {});
// build
if (mounted) {
setState(() {
//
});
}
}
}

View File

@ -443,7 +443,7 @@ class _CertificateDetailPageState extends State<CertificateDetailPage> {
],
ItemListWidget.selectableLineTitleTextRightButton(
label: '证书类型:',
label: '证书作业类型:',
isEditable: widget.model == CertifitcateEditMode.add,
text: pd['typeName'] ?? '请选择',
isRequired: widget.model == CertifitcateEditMode.add,

View File

@ -1,7 +1,5 @@
// file: mine_page.dart
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
@ -21,13 +19,10 @@ import 'package:qhd_prevention/tools/tools.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'certificate/certificate_list_page.dart';
import 'package:qhd_prevention/common/route_service.dart';
import 'package:qhd_prevention/common/route_model.dart';
class MinePage extends StatefulWidget {
const MinePage({super.key, required this.isChooseFirm});
final bool isChooseFirm;
final bool isChooseFirm;
@override
State<MinePage> createState() => MinePageState();
}
@ -44,152 +39,22 @@ class MinePageState extends State<MinePage> {
String name = '登录/注册';
String phone = '';
/// UI // menuPerm(s)
/// perm
final List<Map<String, dynamic>> _allSettings = [
{
'title': '我的信息',
'icon': 'assets/images/ico9.png',
'perms': ['my-center-My-Information'],
'action': 'userinfo',
},
{
'title': '修改密码',
'icon': 'assets/images/ico16.png',
'perms': ['my-center-Change-Password'],
'action': 'changePwd',
},
{
'title': '扫码入职',
'icon': 'assets/images/ico10.png',
// perm []
'perms': ['dashboard-scan'],
'action': 'scanOnboarding',
},
{
'title': '人脸认证',
'icon': 'assets/images/ico11.png',
'perms': ['my-center-Face-Authentication'],
'action': 'face',
},
{
'title': '证书信息',
'icon': 'assets/images/ico12.png',
'perms': ['my-center-Certificate-Information'],
'action': 'certificate',
},
// {
// 'title': '版本更新',
// 'icon': 'assets/images/ico14.png',
// 'perms': ['my-center-Version-Update'],
// 'action': 'version',
// },
// {
// 'title': '关于我们',
// 'icon': 'assets/images/ico15.png',
// 'perms': ['my-center-About-Us'],
// 'action': 'about',
// },
{
'title': '切换账户',
'icon': 'assets/images/ico_switch.png',
// widget.isChooseFirm true
'perms': ['my-center-Switch-Account'],
'action': 'changeAccount',
},
{
'title': '账户注销',
'icon': 'assets/images/ico_quit.png',
//
'perms': ['my-center-User-Logout', 'my-center-Logout'],
'action': 'logout',
},
];
// _allSettings
late List<bool> _visible;
void onRouteConfigLoaded() {
if (mounted) {
setState(() {
// update listener
// _updateMenuVisibility();
});
}
}
@override
void initState() {
// TODO: implement initState
super.initState();
_getUserInfo();
// /
_visible = List<bool>.filled(_allSettings.length, true);
//
RouteService().addListener(_onRouteServiceUpdated);
// route
WidgetsBinding.instance.addPostFrameCallback((_) => _updateVisibilityFromRoute());
}
@override
void dispose() {
try {
RouteService().removeListener(_onRouteServiceUpdated);
} catch (_) {}
super.dispose();
}
void _onRouteServiceUpdated() {
_updateVisibilityFromRoute();
}
/// RouteService
void _updateVisibilityFromRoute() {
final rs = RouteService();
// mainTabs visible
if (rs.mainTabs.isEmpty) {
return;
}
final List<bool> next = List<bool>.filled(_allSettings.length, false);
for (int i = 0; i < _allSettings.length; i++) {
final perms = (_allSettings[i]['perms'] ?? []) as List<String>;
if (perms.isEmpty) {
// /
next[i] = true;
continue;
}
// perm
bool anyFound = false;
for (final p in perms) {
final node = rs.findRouteByPerm(p);
if (node != null) {
// rs.findRouteByPerm visible RouteService
// showFlag==1 showFlag==0 ()
if (node.showFlag == 1 || node.visible) {
anyFound = true;
break;
}
}
}
next[i] = anyFound;
}
// _visible setState
if (!listEquals(next, _visible)) {
setState(() {
_visible = next;
});
}
}
//
//
Future<void> _getUserInfo() async {
final res = await BasicInfoApi.getUserMessage(
'${SessionService.instance.accountId}',
@ -204,8 +69,111 @@ class MinePageState extends State<MinePage> {
});
}
}
@override
Widget build(BuildContext context) {
final double headerHeight = 300.0;
final double overlap = 100.0;
return SizedBox(
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
Positioned(
top: 0,
left: 0,
right: 0,
height: headerHeight,
child: _buildHeaderSection(),
),
Positioned.fill(
child: NotificationListener<OverscrollIndicatorNotification>(
onNotification: (overscroll) {
overscroll.disallowIndicator();
return false;
},
child: ListView(
padding: EdgeInsets.only(
top: headerHeight - overlap,
bottom: 24,
left: 0,
right: 0,
),
children: [
_buildSettingsList(),
SizedBox(height: 15),
Padding(
padding: EdgeInsetsGeometry.symmetric(horizontal: 15),
child: CustomButton(
text: '退出登录',
textStyle: TextStyle(fontSize: 16),
backgroundColor: Colors.blue,
// borderRadius: 15,
onPressed: () {
CustomAlertDialog.showConfirm(
context,
title: '确认退出',
content: '确定要退出当前账号吗',
onConfirm: () async {
// await AuthService.logout(); //
// if (!mounted) return;
//
await _clearUserSession();
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => const LoginPage(),
),
(Route<dynamic> route) => false,
);
},
);
},
),
),
],
),
),
),
],
),
);
}
Widget _buildHeaderSection() {
return Stack(
alignment: const FractionalOffset(0.5, 0),
children: [
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child:
Image.asset(
"assets/images/my_bg.png",
width: MediaQuery.of(context).size.width, //
fit: BoxFit.cover,
),
),
Positioned(
top: 51,
child: Text(
"我的",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
//
_buildSloganSection(),
],
);
}
Future<void> _logout() async {
LoadingDialogHelper.show();
///
@ -224,7 +192,8 @@ class MinePageState extends State<MinePage> {
context,
title: '温馨提示',
content: '注销后您的所有信息将会被删除\n请确认是否注销。 ',
onConfirm: () {},
onConfirm: () {
},
);
if (result) {
CustomAlertDialog.showInputWithCode(
@ -240,7 +209,8 @@ class MinePageState extends State<MinePage> {
},
onConfirm: (code) async {
_quit(code);
});
}
);
}
}
} else {
@ -253,8 +223,8 @@ class MinePageState extends State<MinePage> {
Future<void> _quit(String code) async {
LoadingDialogHelper.show();
Map data = {
'id': SessionService.instance.accountId,
'phoneCode': code,
'id' : SessionService.instance.accountId,
'phoneCode' : code,
};
await BasicInfoApi.logout(data).then((res) async {
LoadingDialogHelper.dismiss();
@ -263,7 +233,8 @@ class MinePageState extends State<MinePage> {
await SessionService.instance.clear(clearPrefs: true);
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => const LoginPage()),
MaterialPageRoute(
builder: (_) => const LoginPage()),
);
} else {
ToastUtil.showNormal(context, res['errMessage'] ?? '');
@ -275,21 +246,28 @@ class MinePageState extends State<MinePage> {
final headerUrl = SessionService.instance.userData?.userAvatarUrl ?? '';
return Container(
margin: const EdgeInsets.fromLTRB(0, 100, 0, 0),
margin: EdgeInsets.fromLTRB(0, 100, 0, 0),
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween, //
// crossAxisAlignment: CrossAxisAlignment.center, //
children: [
Row(
children: [
const CircleAvatar(
backgroundImage: AssetImage("assets/images/yingyong11.png"),
radius: 30,
),
headerUrl.isEmpty
? const CircleAvatar(
backgroundImage: AssetImage("assets/images/my_bg.png"),
radius: 30,
)
: CircleAvatar(
backgroundImage: NetworkImage(ApiService.baseImgPath + headerUrl),
radius: 30,
),
const SizedBox(width: 16),
Text(
name,
style: const TextStyle(
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
@ -303,6 +281,136 @@ class MinePageState extends State<MinePage> {
);
}
Widget _buildSettingsList() {
return Container(
margin: const EdgeInsets.fromLTRB(20, 0, 20, 0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 2,
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
child: Column(
children: [
_buildSettingItem(
title: "我的信息",
icon: "assets/images/ico9.png",
value: notificationsEnabled,
onChanged: (value) async {
await pushPage(
FullUserinfoPage(isEidt: false, isChooseFirm: true),
context,
);
},
),
_buildSettingItem(
title: "修改密码",
icon: "assets/images/ico16.png",
value: notificationsEnabled,
onChanged: (value) async {
await pushPage(MineSetPwdPage('0'), context);
},
),
_buildSettingItem(
title: "扫码入职",
icon: "assets/images/ico10.png",
value: scanAuthentication,
onChanged: (value) async {
final result = await pushPage(
ScanPage(type: ScanType.Onboarding),
context,
);
if (result == null) {
return;
}
pushPage(OnboardingFullPage(scanData: result), context);
},
),
_buildSettingItem(
title: "人脸认证",
icon: "assets/images/ico11.png",
value: faceAuthentication,
onChanged: (value) {
pushPage(
const FaceRecognitionPage(
studentId: '',
data: {},
mode: FaceMode.setUpdata,
),
context,
);
},
),
_buildSettingItem(
title: "证书信息",
icon: "assets/images/ico12.png",
value: passwordChanged,
onChanged: (value) {
pushPage(
const CertificateListPage(),
context,
);
},
),
// _buildSettingItem(
// title: "问题反馈",
// icon: "assets/images/ico13.png",
// value: passwordChanged,
// onChanged: (value) {
// ToastUtil.showNormal(context, '需求待定');
// // pushPage(FeedbackPage(), context);
// },
// ),
// const Divider(height: 1, indent: 60),
_buildSettingItem(
title: "版本更新",
icon: "assets/images/ico14.png",
value: updateAvailable,
onChanged: (value) => setState(() => updateAvailable = value!),
),
_buildSettingItem(
title: "关于我们",
icon: "assets/images/ico15.png",
value: logoutSelected,
onChanged: (value) {
setState(() => logoutSelected = value!);
},
),
if (widget.isChooseFirm)
_buildSettingItem(
title: "切换账户",
icon: "assets/images/ico_switch.png",
value: logoutSelected,
onChanged: (value) {
pushPage(MineChangeFirmPage(), context);
},
),
_buildSettingItem(
title: "账户注销",
icon: "assets/images/ico_quit.png",
value: logoutSelected,
onChanged: (value) {
_logout();
},
),
],
),
);
}
Widget _buildSettingItem({
required String title,
required String icon,
@ -327,9 +435,16 @@ class MinePageState extends State<MinePage> {
title,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
),
trailing: Transform.scale(
scale: 1.2,
child: const Icon(Icons.chevron_right),
child: Icon(Icons.chevron_right),
// Image.asset(
// "assets/images/right.png",
// fit: BoxFit.cover,
// width: 15,
// height: 15,
// ),
),
),
);
@ -339,160 +454,4 @@ class MinePageState extends State<MinePage> {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('isLoggedIn'); //
}
void _onSettingTapAction(String action) async {
switch (action) {
case 'userinfo':
await pushPage(FullUserinfoPage(isEidt: false, isChooseFirm: true), context);
break;
case 'changePwd':
await pushPage(MineSetPwdPage('0'), context);
break;
case 'scanOnboarding':
final result = await pushPage(ScanPage(type: ScanType.Onboarding), context);
if (result == null) return;
pushPage(OnboardingFullPage(scanData: result), context);
break;
case 'face':
pushPage(const FaceRecognitionPage(studentId: '', data: {}, mode: FaceMode.setUpdata), context);
break;
case 'certificate':
pushPage(const CertificateListPage(), context);
break;
case 'version':
//
ToastUtil.showNormal(context, '功能开发中...');
break;
case 'about':
//
ToastUtil.showNormal(context, '功能开发中...');
break;
case 'changeAccount':
pushPage(MineChangeFirmPage(), context);
break;
case 'logout':
_logout();
break;
default:
break;
}
}
Widget _buildSettingsList() {
final children = <Widget>[];
for (int i = 0; i < _allSettings.length; i++) {
// _visible
if (i >= _visible.length) continue;
if (!_visible[i]) continue;
final item = _allSettings[i];
final title = item['title'] as String;
// isChooseFirm true
if (title == '切换账户' && !widget.isChooseFirm) continue;
children.add(_buildSettingItem(
title: title,
icon: item['icon'] as String,
value: false,
onChanged: (_) => _onSettingTapAction(item['action'] as String),
));
}
return Container(
margin: const EdgeInsets.fromLTRB(20, 0, 20, 0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 2,
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
child: Column(
children: children,
),
);
}
@override
Widget build(BuildContext context) {
final double headerHeight = 300.0;
final double overlap = 100.0;
return SizedBox(
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
Positioned(top: 0, left: 0, right: 0, height: headerHeight, child: _buildHeaderSection()),
Positioned.fill(
child: NotificationListener<OverscrollIndicatorNotification>(
onNotification: (overscroll) {
overscroll.disallowIndicator();
return false;
},
child: ListView(
padding: EdgeInsets.only(top: headerHeight - overlap, bottom: 24, left: 0, right: 0),
children: [
_buildSettingsList(),
const SizedBox(height: 15),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: CustomButton(
text: '退出登录',
textStyle: const TextStyle(fontSize: 16),
backgroundColor: Colors.blue,
onPressed: () {
CustomAlertDialog.showConfirm(
context,
title: '确认退出',
content: '确定要退出当前账号吗',
onConfirm: () async {
await _clearUserSession();
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => const LoginPage()),
(Route<dynamic> route) => false,
);
},
);
},
),
),
],
),
),
),
],
),
);
}
Widget _buildHeaderSection() {
return Stack(
alignment: const FractionalOffset(0.5, 0),
children: [
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Image.asset(
"assets/images/my_bg.png",
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
),
),
const Positioned(
top: 51,
child: Text(
"我的",
style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold),
),
),
_buildSloganSection(),
],
);
}
}

View File

@ -1,131 +0,0 @@
import 'package:flutter/material.dart';
import 'package:qhd_prevention/constants/app_enums.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/http/modules/edu_api.dart';
import 'package:qhd_prevention/http/modules/file_api.dart';
import 'package:qhd_prevention/pages/home/Study/study_take_exam_page.dart';
import 'package:qhd_prevention/pages/mine/face_ecognition_page.dart';
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
import 'package:qhd_prevention/pages/mine/onboarding_full_page.dart';
import 'package:qhd_prevention/services/SessionService.dart';
import 'package:qhd_prevention/tools/tools.dart';
class ScanService {
static void scan(BuildContext context, final result) async {
if (FormUtils.hasValue(result, 'classId')) { // 线
int type = result['type'] ?? 0;
final data = {
...result,
'phone': SessionService.instance.userData?.phone ?? '',
'type': type,
};
LoadingDialogHelper.show();
//
final response = await EduApi.checkSignIn(data);
LoadingDialogHelper.hide();
if (response['success']) {
//
final filePath = await pushPage(
const FaceRecognitionPage(
studentId: '',
data: {},
mode: FaceMode.study,
),
context,
);
final faceData = response['data'];
if (filePath != null) {
//
try {
LoadingDialogHelper.show();
final response = await EduApi.compareFace({
'type': data['type'],
'studentId': faceData['studentId'],
}, filePath);
final faceResultData = response['data'];
if (response['success']) {
final signData = {
'id': faceResultData['id'] ?? '',
'studentId': faceResultData['studentId'] ?? '',
'type': data['type']?? '',
'classId': faceResultData['classId'] ?? '',
'studentSignId':faceResultData['studentSignId']??''
};
ScanService.signUpload(signData, type, context);
} else {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, response['errMessage'] ?? '验证失败');
}
} catch (e) {
ToastUtil.showNormal(context,'验证失败');
LoadingDialogHelper.hide();
print(e);
}
} else {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, '签到失败');
}
} else {
ToastUtil.showNormal(context, response['errMessage'] ?? '签到失败');
}
}
if (FormUtils.hasValue(result, 'corpinfoId')) { //
pushPage(OnboardingFullPage(scanData: result), context);
}
}
//
static Future<void> signUpload(Map data, int type, BuildContext context) async {
LoadingDialogHelper.hide();
UploadFileType fileType =
type == 1
? UploadFileType.onlineLearningSignSignature
: UploadFileType.onlineLearningExamSignature;
final signPath = await pushPage(MineSignPage(), context);
if (signPath != null) {
//
try {
LoadingDialogHelper.show();
//
final response = await FileApi.uploadFile(signPath, fileType, '');
if (response['success']) {
data['signUrl'] = response['data']['filePath'];
final signResult = await EduApi.uploadSignature(data);
LoadingDialogHelper.hide();
if (signResult['success']) {
if (type == 1) {
ToastUtil.showNormal(context, '签到成功');
} else {
//
final examResult = await EduApi.getExamDetail(
data['classId'] ?? '',
);
LoadingDialogHelper.hide();
//
pushPage(
StudyTakeExamPage(
examInfo: examResult['data'] ?? {}, signInfo: data),
context,
);
}
} else {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, signResult['errMessage'] ?? '');
}
} else {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, response['errMessage'] ?? '');
}
} catch (e) {
LoadingDialogHelper.hide();
print(e);
}
}
}
}

View File

@ -953,10 +953,10 @@ packages:
dependency: "direct main"
description:
name: photo_manager
sha256: fb3bc8ea653370f88742b3baa304700107c83d12748aa58b2b9f2ed3ef15e6c2
sha256: "99355f3b3591a00416cc787bbf7f04510f672d602814e0063bf4dc40603041f0"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "3.9.0"
version: "3.8.0"
photo_manager_image_provider:
dependency: transitive
description:

View File

@ -69,7 +69,7 @@ dependencies:
# 相册
image_picker: ^1.1.2
wechat_assets_picker: ^9.5.1
photo_manager: ^3.9.0
photo_manager: ^3.7.1
file_picker: ^10.3.2
# 日历
table_calendar: ^3.2.0
@ -155,7 +155,6 @@ flutter:
- assets/map/
- assets/tabbar/
- assets/study/
- assets/route/routes.txt
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg