web端修复

This commit is contained in:
Developer
2026-04-01 01:34:22 +08:00
parent ab9961853d
commit 6517a78c7e
12 changed files with 2390 additions and 46 deletions

View File

@@ -0,0 +1,545 @@
# 诗词收录系统 - API 使用文档
## 概述
本文档描述诗词收录系统的 API 接口使用方法。
## 基础信息
- **API 地址**: `api.php`
- **请求方式**: GET/POST
- **返回格式**: JSON
- **字符编码**: UTF-8
## API 接口
### 1. 获取分类列表
获取所有可用的诗词分类。
**接口地址**: `api.php?api=categories`
**请求方式**: GET
**请求参数**: 无
**返回示例**:
```json
{
"ok": true,
"categories": [
{
"id": "1",
"sid": "1",
"icon": "fa-paper-plane",
"catename": "诗词句",
"alias": null,
"create_time": "2026-03-12 04:17:50",
"update_time": "2026-03-13 02:12:54"
}
],
"debug": {
"current_dir": "/www/wwwroot/yy.vogov.cn/api/app",
"categories_count": 3
}
}
```
---
### 2. 检查诗词名称是否存在
检查指定的诗词名称是否已存在于数据库中(支持相似度检查)。
**接口地址**: `api.php?api=check-name`
**请求方式**: POST
**请求参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| name | string | 是 | 诗词名称/参考语句 |
| threshold | int | 否 | 相似度阈值0-100默认 80 |
**请求示例**:
```javascript
const formData = new FormData();
formData.append('name', '盈盈一水间,脉脉不得语');
formData.append('threshold', 80);
const response = await fetch('api.php?api=check-name', {
method: 'POST',
body: formData
});
const data = await response.json();
```
**返回示例**:
**无相似内容**:
```json
{
"ok": true,
"exists": false,
"similar_count": 0,
"max_similarity": 0,
"threshold": 80
}
```
**发现相似内容**:
```json
{
"ok": true,
"exists": true,
"similar_count": 2,
"max_similarity": 95,
"threshold": 80
}
```
**返回字段说明**:
| 字段名 | 类型 | 说明 |
|--------|------|------|
| ok | boolean | 请求是否成功 |
| exists | boolean | 是否存在相似内容true=存在false=不存在 |
| similar_count | int | 相似内容条数 |
| max_similarity | float | 最高相似度百分比0-100 |
| threshold | int | 使用的相似度阈值 |
---
### 3. 提交诗词收录申请
提交诗词收录申请到数据库。
**接口地址**: `api.php?api=submit`
**请求方式**: POST
**请求参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| name | string | 是 | 诗词名称/参考语句 |
| catename | string | 是 | 分类名称 |
| url | string | 是 | 诗人和标题 |
| keywords | string | 是 | 关键词,多个用逗号分隔 |
| introduce | string | 是 | 诗词介绍 |
| img | string | 否 | 平台/配图,默认值: 'default' |
| captcha | string | 是 | 人机验证码 |
| threshold | int | 否 | 相似度阈值0-100默认 80 |
**请求示例**:
```javascript
const formData = new FormData();
formData.append('name', '盈盈一水间,脉脉不得语');
formData.append('catename', '诗词句');
formData.append('url', '古诗十九首');
formData.append('keywords', '爱情,古诗,离别');
formData.append('introduce', '《迢迢牵牛星》是产生于汉代的一首文人五言诗...');
formData.append('img', 'iOS Swift');
formData.append('captcha', '1234');
formData.append('threshold', 80);
const response = await fetch('api.php?api=submit', {
method: 'POST',
body: formData
});
const data = await response.json();
```
**返回示例**:
**成功**:
```json
{
"ok": true,
"message": "✅ 提交成功!等待审核",
"debug": {
"input_data": {...},
"insert_result": true,
"last_insert_id": "123"
}
}
```
**失败**:
```json
{
"ok": false,
"error": "该诗词已存在!",
"debug": {...}
}
```
**返回字段说明**:
| 字段名 | 类型 | 说明 |
|--------|------|------|
| ok | boolean | 请求是否成功 |
| message | string | 成功消息(仅成功时返回) |
| error | string | 错误消息(仅失败时返回) |
| debug | object | 调试信息 |
---
## 在 App 中的使用方法
### Android (Kotlin)
```kotlin
// 获取分类
suspend fun getCategories(): List<Category> {
val response = OkHttpClient().newCall(
Request.Builder()
.url("https://your-domain.com/api.php?api=categories")
.build()
).execute()
val json = JSONObject(response.body?.string())
val categoriesArray = json.getJSONArray("categories")
val categories = mutableListOf<Category>()
for (i in 0 until categoriesArray.length()) {
val cat = categoriesArray.getJSONObject(i)
categories.add(Category(cat.getString("catename")))
}
return categories
}
// 检查名称
suspend fun checkName(name: String, threshold: Int = 80): CheckResult {
val formBody = FormBody.Builder()
.add("name", name)
.add("threshold", threshold.toString())
.build()
val response = OkHttpClient().newCall(
Request.Builder()
.url("https://your-domain.com/api.php?api=check-name")
.post(formBody)
.build()
).execute()
val json = JSONObject(response.body?.string())
return CheckResult(
exists = json.getBoolean("exists"),
similarCount = json.getInt("similar_count"),
maxSimilarity = json.getDouble("max_similarity"),
threshold = json.getInt("threshold")
)
}
// 提交收录
suspend fun submitPoem(data: PoemData): Boolean {
val formBody = FormBody.Builder()
.add("name", data.name)
.add("catename", data.catename)
.add("url", data.url)
.add("keywords", data.keywords)
.add("introduce", data.introduce)
.add("img", data.img ?: "default")
.add("captcha", data.captcha)
.add("threshold", data.threshold?.toString() ?: "80")
.build()
val response = OkHttpClient().newCall(
Request.Builder()
.url("https://your-domain.com/api.php?api=submit")
.post(formBody)
.build()
).execute()
val json = JSONObject(response.body?.string())
return json.getBoolean("ok")
}
```
### iOS (Swift)
```swift
//
func getCategories(completion: @escaping ([String]?, Error?) -> Void) {
guard let url = URL(string: "https://your-domain.com/api.php?api=categories") else {
completion(nil, NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"]))
return
}
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
completion(nil, error)
return
}
guard let data = data else {
completion(nil, NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "No data"]))
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let categories = json["categories"] as? [[String: Any]] {
let categoryNames = categories.compactMap { $0["catename"] as? String }
completion(categoryNames, nil)
}
} catch {
completion(nil, error)
}
}.resume()
}
//
func checkName(name: String, threshold: Int = 80, completion: @escaping (CheckResult?, Error?) -> Void) {
guard let apiUrl = URL(string: "https://your-domain.com/api.php?api=check-name") else {
completion(nil, NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"]))
return
}
var request = URLRequest(url: apiUrl)
request.httpMethod = "POST"
let parameters = [
"name": name,
"threshold": "\(threshold)"
]
request.httpBody = parameters.percentEncoded()
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
completion(nil, error)
return
}
guard let data = data else {
completion(nil, NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "No data"]))
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let exists = json["exists"] as? Bool,
let similarCount = json["similar_count"] as? Int,
let maxSimilarity = json["max_similarity"] as? Double,
let threshold = json["threshold"] as? Int {
let result = CheckResult(
exists: exists,
similarCount: similarCount,
maxSimilarity: maxSimilarity,
threshold: threshold
)
completion(result, nil)
}
} catch {
completion(nil, error)
}
}.resume()
}
//
func submitPoem(name: String, catename: String, url: String, keywords: String, introduce: String, img: String?, captcha: String, threshold: Int = 80, completion: @escaping (Bool, String?) -> Void) {
guard let apiUrl = URL(string: "https://your-domain.com/api.php?api=submit") else {
completion(false, "Invalid URL")
return
}
var request = URLRequest(url: apiUrl)
request.httpMethod = "POST"
let parameters = [
"name": name,
"catename": catename,
"url": url,
"keywords": keywords,
"introduce": introduce,
"img": img ?? "default",
"captcha": captcha,
"threshold": "\(threshold)"
]
request.httpBody = parameters.percentEncoded()
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
completion(false, error.localizedDescription)
return
}
guard let data = data else {
completion(false, "No data")
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let ok = json["ok"] as? Bool {
let message = json["message"] as? String ?? json["error"] as? String
completion(ok, message)
}
} catch {
completion(false, error.localizedDescription)
}
}.resume()
}
extension Dictionary {
func percentEncoded() -> Data? {
return map { key, value in
let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
return escapedKey + "=" + escapedValue
}
.joined(separator: "&")
.data(using: .utf8)
}
}
extension CharacterSet {
static let urlQueryValueAllowed: CharacterSet = {
let generalDelimitersToEncode = ":#[]@"
let subDelimitersToEncode = "!$&'()*+,;="
var allowed = CharacterSet.urlQueryAllowed
allowed.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
return allowed
}()
}
```
### Flutter (Dart)
```dart
import 'package:http/http.dart' as http;
import 'dart:convert';
// 获取分类
Future<List<String>> getCategories() async {
final response = await http.get(
Uri.parse('https://your-domain.com/api.php?api=categories'),
);
if (response.statusCode == 200) {
final data = json.decode(response.body);
final List<dynamic> categories = data['categories'];
return categories.map((cat) => cat['catename'] as String).toList();
} else {
throw Exception('Failed to load categories');
}
}
// 检查名称
Future<CheckResult> checkName({
required String name,
int threshold = 80,
}) async {
final response = await http.post(
Uri.parse('https://your-domain.com/api.php?api=check-name'),
body: {
'name': name,
'threshold': threshold.toString(),
},
);
if (response.statusCode == 200) {
final data = json.decode(response.body);
return CheckResult(
exists: data['exists'] as bool,
similarCount: data['similar_count'] as int,
maxSimilarity: (data['max_similarity'] as num).toDouble(),
threshold: data['threshold'] as int,
);
} else {
throw Exception('Failed to check name');
}
}
// 提交收录
Future<bool> submitPoem({
required String name,
required String catename,
required String url,
required String keywords,
required String introduce,
String? img,
required String captcha,
int threshold = 80,
}) async {
final response = await http.post(
Uri.parse('https://your-domain.com/api.php?api=submit'),
body: {
'name': name,
'catename': catename,
'url': url,
'keywords': keywords,
'introduce': introduce,
'img': img ?? 'default',
'captcha': captcha,
'threshold': threshold.toString(),
},
);
if (response.statusCode == 200) {
final data = json.decode(response.body);
return data['ok'] as bool;
} else {
throw Exception('Failed to submit');
}
}
```
---
## 错误码说明
| 错误信息 | 说明 |
|----------|------|
| 缺少必填字段xxx | 必填字段未填写 |
| 该诗词已存在! | 诗词名称已在数据库中,或相似度超过阈值 |
| ❌ 数据库写入失败:无法插入数据 | 数据库插入失败 |
| 验证码错误,请重新输入 | 人机验证码错误 |
| 提交过于频繁,请稍后再试 | 频率限制1分钟内只能提交3次 |
---
## 相似度说明
系统使用 **Levenshtein 距离算法** 计算文本相似度:
1. **文本清理**:自动去除标点符号和空格后比较
2. **阈值设置**0-100%,默认 80%
3. **判断规则**:相似度 ≥ 阈值 则认为是重复内容
**示例**
- "盈盈一水间,脉脉不得语"
- "盈盈一水间,脉脉不得语。"(相似度约 95%
- "盈盈一水间,脉脉不得"(相似度约 85%
---
## 注意事项
1. **字符编码**: 所有请求和响应都使用 UTF-8 编码
2. **人机验证**: 提交接口必须提供正确的验证码
3. **频率限制**: 同一 IP 1分钟内最多提交 3 次
4. **相似度检查**: check-name 和 submit 接口都会进行相似度检查
5. **数据安全**: 所有用户输入都会经过安全处理
6. **调试信息**: API 返回包含 debug 字段,方便开发调试,生产环境可忽略
---
## 更新日志
- **v1.0.12**: 添加相似度验证功能,支持可配置阈值
- **v1.0.11**: 修改验证表为 pre_site
- **v1.0.10**: 添加人机验证功能和频率限制
- **v1.0.9**: 添加结果Modal对话框
- **v1.0.8**: 添加检测按钮和提交前确认

66
lib/services/stats.php Normal file
View File

@@ -0,0 +1,66 @@
<?php
require_once('../../includes/common.php');
header('Content-Type: application/json; charset=UTF-8');
header('Access-Control-Allow-Origin: *');
try {
$stats = [];
$stats['count_category'] = $DB->count('category');
$stats['count_site'] = $DB->count('site');
$stats['count_apply'] = $DB->count('apply', array('reject' => 0));
$stats['count_apply_reject'] = $DB->count('apply', array('reject' => 1));
$stats['count_article'] = $DB->count('article');
$stats['count_article_category'] = $DB->count('article_category');
$stats['count_notice'] = $DB->count('notice');
$stats['count_link'] = $DB->count('link');
$stats['count_tags'] = 131;
$top_hits_day = $DB->find('site', 'id, name', array('date' => date("Y-m-d", time())), '`hits_day` desc');
$top_hits_month = $DB->find('site', 'id, name', array('datem' => date("Y-m", time())), '`hits_month` desc');
$top_hits_total = $DB->find('site', 'id, name', null, '`hits_total` desc');
$top_like = $DB->find('site', 'id, name', null, '`like` desc');
$cumulative_hits_result = $DB->query("SELECT SUM(hits_total) as total FROM pre_site")->fetch();
$cumulative_likes_result = $DB->query("SELECT SUM(`like`) as total FROM pre_site")->fetch();
$stats['cumulative_hits'] = $cumulative_hits_result['total'] ?? 0;
$stats['cumulative_likes'] = $cumulative_likes_result['total'] ?? 0;
$stats['top_hits_day'] = $top_hits_day ? [
'id' => $top_hits_day['id'],
'name' => $top_hits_day['name']
] : null;
$stats['top_hits_month'] = $top_hits_month ? [
'id' => $top_hits_month['id'],
'name' => $top_hits_month['name']
] : null;
$stats['top_hits_total'] = $top_hits_total ? [
'id' => $top_hits_total['id'],
'name' => $top_hits_total['name']
] : null;
$stats['top_like'] = $top_like ? [
'id' => $top_like['id'],
'name' => $top_like['name']
] : null;
$stats['build_time'] = $conf['build_time'] ?? '';
echo json_encode([
'ok' => true,
'data' => $stats,
'timestamp' => time()
], JSON_UNESCAPED_UNICODE);
} catch (Exception $e) {
echo json_encode([
'ok' => false,
'error' => $e->getMessage()
], JSON_UNESCAPED_UNICODE);
}

View File

@@ -0,0 +1,11 @@
import 'wakelock_service_web.dart' if (dart.library.io) 'wakelock_service_io.dart';
abstract class WakelockService {
static final WakelockService instance = getWakelockService();
Future<void> enable();
Future<void> disable();
Future<bool> isEnabled();
}
WakelockService getWakelockService() => getWakelockServiceImpl();

View File

@@ -0,0 +1,21 @@
import 'package:wakelock_plus/wakelock_plus.dart';
import 'wakelock_service.dart';
class WakelockServiceIO implements WakelockService {
@override
Future<void> enable() async {
await WakelockPlus.enable();
}
@override
Future<void> disable() async {
await WakelockPlus.disable();
}
@override
Future<bool> isEnabled() async {
return await WakelockPlus.enabled;
}
}
WakelockService getWakelockServiceImpl() => WakelockServiceIO();

View File

@@ -0,0 +1,20 @@
import 'wakelock_service.dart';
class WakelockServiceWeb implements WakelockService {
@override
Future<void> enable() async {
// Web 平台不支持屏幕常亮功能
}
@override
Future<void> disable() async {
// Web 平台不支持屏幕常亮功能
}
@override
Future<bool> isEnabled() async {
return false;
}
}
WakelockService getWakelockServiceImpl() => WakelockServiceWeb();

View File

@@ -0,0 +1,216 @@
# 统计 API 接口文档
## 概述
获取网站统计信息的 API 接口,返回分类数量、收录数量、热度统计等数据。
## 基础信息
- **接口地址**: `https://yy.vogov.cn/api/app/stats.php`
- **请求方式**: GET
- **返回格式**: JSON
- **字符编码**: UTF-8
- **支持跨域**: 是(`Access-Control-Allow-Origin: *`
## 请求参数
无需任何参数,直接 GET 请求即可。
## 返回示例
```json
{
"ok": true,
"data": {
"count_category": 3,
"count_site": 15807,
"count_apply": 14,
"count_apply_reject": 3,
"count_article": 2,
"count_article_category": 4,
"count_notice": 2,
"count_link": 3,
"count_tags": 131,
"cumulative_hits": "16887",
"cumulative_likes": "272",
"top_hits_day": {
"id": "7559",
"name": "除却天边月,没人知。人有悲欢离合,月有阴晴圆缺,此事古难全。"
},
"top_hits_month": {
"id": "461",
"name": "人有悲欢离合,月有阴晴圆缺,此事古难全。"
},
"top_hits_total": {
"id": "1",
"name": "井鱼焉知身在渊,错把方寸作世间‌"
},
"top_like": {
"id": "5876",
"name": "世间无比酒,天下有名楼。"
},
"build_time": "2026-03-04"
},
"timestamp": 1774977191
}
```
## 返回字段说明
### 基础字段
| 字段名 | 类型 | 说明 |
|--------|------|------|
| ok | boolean | 请求是否成功 |
| data | object | 统计数据对象 |
| timestamp | int | 服务器时间戳 |
### data 对象字段
#### 数量统计
| 字段名 | 类型 | 说明 |
|--------|------|------|
| count_category | int | 已开设分类数量 |
| count_site | int | 已收录诗句数量 |
| count_apply | int | 审核中的申请数量 |
| count_apply_reject | int | 已拒绝的申请数量 |
| count_article | int | 文章数量 |
| count_article_category | int | 文章分类数量 |
| count_notice | int | 已发布公告数量 |
| count_link | int | 开发者人数 |
| count_tags | int | 分类标签数量 |
#### 热度统计
| 字段名 | 类型 | 说明 |
|--------|------|------|
| cumulative_hits | string | 累计热度次数 |
| cumulative_likes | string | 累计点赞数量 |
#### 热门内容
| 字段名 | 类型 | 说明 |
|--------|------|------|
| top_hits_day | object/null | 当天热门诗句 |
| top_hits_month | object/null | 本月热门诗句 |
| top_hits_total | object/null | 历史最热诗句 |
| top_like | object/null | 最高点赞诗句 |
#### 热门内容对象
| 字段名 | 类型 | 说明 |
|--------|------|------|
| id | string | 诗句 ID |
| name | string | 诗句内容 |
#### 其他
| 字段名 | 类型 | 说明 |
|--------|------|------|
| build_time | string | 建站时间格式YYYY-MM-DD |
## 错误返回
```json
{
"ok": false,
"error": "错误信息"
}
```
## 调用示例
### JavaScript (Fetch)
```javascript
fetch('https://yy.vogov.cn/api/app/stats.php')
.then(response => response.json())
.then(data => {
if (data.ok) {
console.log('已收录诗句:', data.data.count_site);
console.log('当天热门:', data.data.top_hits_day.name);
}
})
.catch(error => console.error('Error:', error));
```
### Flutter (Dart)
```dart
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<StatsData?> getStats() async {
final response = await http.get(
Uri.parse('https://yy.vogov.cn/api/app/stats.php'),
);
if (response.statusCode == 200) {
final data = json.decode(response.body);
if (data['ok'] == true) {
return StatsData.fromJson(data['data']);
}
}
return null;
}
class StatsData {
final int countSite;
final String cumulativeHits;
final TopContent? topHitsDay;
StatsData({
required this.countSite,
required this.cumulativeHits,
this.topHitsDay,
});
factory StatsData.fromJson(Map<String, dynamic> json) {
return StatsData(
countSite: json['count_site'],
cumulativeHits: json['cumulative_hits'],
topHitsDay: json['top_hits_day'] != null
? TopContent.fromJson(json['top_hits_day'])
: null,
);
}
}
class TopContent {
final String id;
final String name;
TopContent({required this.id, required this.name});
factory TopContent.fromJson(Map<String, dynamic> json) {
return TopContent(id: json['id'], name: json['name']);
}
}
```
## 数据来源
数据来源于以下数据库表:
| 表名 | 说明 |
|------|------|
| pre_category | 分类表 |
| pre_site | 收录诗句表 |
| pre_apply | 申请收录表 |
| pre_article | 文章表 |
| pre_article_category | 文章分类表 |
| pre_notice | 公告表 |
| pre_link | 友情链接表 |
## 注意事项
1. **缓存建议**:统计数据变化频率较低,建议客户端缓存 5-10 分钟
2. **空值处理**:热门内容字段可能为 `null`,请做好空值判断
3. **跨域支持**:接口已配置 CORS支持前端直接调用
4. **数据类型**`cumulative_hits``cumulative_likes` 返回的是字符串类型
## 更新日志
- **v1.0.14** (2026-03-30): 新增统计 API 接口

View File

@@ -1,8 +1,9 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:share_plus/share_plus.dart';
import '../../../constants/app_constants.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
import '../../../services/wakelock_service.dart';
import 'dart:io' as io;
class PopMenu extends StatelessWidget {
@@ -44,6 +45,16 @@ class PopMenu extends StatelessWidget {
}
static Future<void> toggleScreenWake(BuildContext context) async {
// Web 平台不支持 wakelock_plus
if (kIsWeb) {
if (context.mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('Web 平台不支持屏幕常亮功能')));
}
return;
}
try {
// 使用 io.Platform 检测平台
final String osName = io.Platform.operatingSystem;
@@ -51,7 +62,7 @@ class PopMenu extends StatelessWidget {
print('Current platform: $osName, version: $osVersion');
// 直接尝试启用屏幕常亮
await WakelockPlus.enable();
await WakelockService.instance.enable();
if (context.mounted) {
ScaffoldMessenger.of(
@@ -59,7 +70,7 @@ class PopMenu extends StatelessWidget {
).showSnackBar(const SnackBar(content: Text('屏幕常亮已开启')));
}
} catch (e, stackTrace) {
print('WakelockPlus error: $e');
print('WakelockService error: $e');
print('Stack trace: $stackTrace');
if (context.mounted) {
// 检查错误类型,判断是否是设备不支持

View File

@@ -9,11 +9,12 @@ import 'dart:io' as io;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import '../../constants/app_constants.dart';
import '../../controllers/history_controller.dart';
import '../../controllers/shared_preferences_storage_controller.dart';
import '../../services/wakelock_service.dart';
import 'history_page.dart';
import 'per_card.dart';
import 'settings/app_fun.dart';
@@ -802,6 +803,11 @@ class _ProfilePageState extends State<ProfilePage>
}
Widget _buildScreenWakeItem() {
// Web 平台不支持屏幕常亮功能,不显示该项
if (kIsWeb) {
return const SizedBox.shrink();
}
// === 屏幕常亮设置项:显示图标、标题和开关 ===
return ListTile(
leading: Icon(
@@ -912,6 +918,16 @@ class _ProfilePageState extends State<ProfilePage>
}
Future<void> _toggleScreenWake(bool enable) async {
// Web 平台不支持 wakelock_plus
if (kIsWeb) {
if (mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('Web 平台不支持屏幕常亮功能')));
}
return;
}
try {
// 使用 io.Platform 检测平台
final String osName = io.Platform.operatingSystem;
@@ -919,14 +935,14 @@ class _ProfilePageState extends State<ProfilePage>
print('Current platform: $osName, version: $osVersion');
if (enable) {
await WakelockPlus.enable();
await WakelockService.instance.enable();
if (mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('屏幕常亮已开启')));
}
} else {
await WakelockPlus.disable();
await WakelockService.instance.disable();
if (mounted) {
ScaffoldMessenger.of(
context,
@@ -938,7 +954,7 @@ class _ProfilePageState extends State<ProfilePage>
_isScreenWakeEnabled = enable;
});
} catch (e, stackTrace) {
print('WakelockPlus error: $e');
print('WakelockService error: $e');
print('Stack trace: $stackTrace');
if (mounted) {
// 检查错误类型,判断是否是设备不支持