初始化
This commit is contained in:
17
device/App.vue
Normal file
17
device/App.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script>
|
||||
export default {
|
||||
onLaunch: function() {
|
||||
console.log('App Launch')
|
||||
},
|
||||
onShow: function() {
|
||||
console.log('App Show')
|
||||
},
|
||||
onHide: function() {
|
||||
console.log('App Hide')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/*每个页面公共css */
|
||||
</style>
|
||||
20
device/index.html
Normal file
20
device/index.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<script>
|
||||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||
CSS.supports('top: constant(a)'))
|
||||
document.write(
|
||||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||
</script>
|
||||
<title></title>
|
||||
<!--preload-links-->
|
||||
<!--app-context-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"><!--app-html--></div>
|
||||
<script type="module" src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
22
device/main.js
Normal file
22
device/main.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import App from './App'
|
||||
|
||||
// #ifndef VUE3
|
||||
import Vue from 'vue'
|
||||
import './uni.promisify.adaptor'
|
||||
Vue.config.productionTip = false
|
||||
App.mpType = 'app'
|
||||
const app = new Vue({
|
||||
...App
|
||||
})
|
||||
app.$mount()
|
||||
// #endif
|
||||
|
||||
// #ifdef VUE3
|
||||
import { createSSRApp } from 'vue'
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
return {
|
||||
app
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
87
device/manifest.json
Normal file
87
device/manifest.json
Normal file
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"name" : "device",
|
||||
"appid" : "__UNI__8CC071F",
|
||||
"description" : "设备信息扫描系统",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
"transformPx" : false,
|
||||
"app-plus" : {
|
||||
"usingComponents" : true,
|
||||
"splashscreen" : {
|
||||
"alwaysShowBeforeRender" : true,
|
||||
"waiting" : true,
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
"modules" : {
|
||||
"Storage" : {}
|
||||
},
|
||||
"distribute" : {
|
||||
"android" : {
|
||||
"permissions" : [
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>"
|
||||
]
|
||||
},
|
||||
"ios" : {
|
||||
"dSYMs" : false
|
||||
},
|
||||
"icons" : {
|
||||
"android" : {
|
||||
"hdpi" : "unpackage/res/icons/72x72.png",
|
||||
"xhdpi" : "unpackage/res/icons/96x96.png",
|
||||
"xxhdpi" : "unpackage/res/icons/144x144.png",
|
||||
"xxxhdpi" : "unpackage/res/icons/192x192.png"
|
||||
},
|
||||
"ios" : {
|
||||
"appstore" : "unpackage/res/icons/1024x1024.png",
|
||||
"ipad" : {
|
||||
"app" : "unpackage/res/icons/76x76.png",
|
||||
"app@2x" : "unpackage/res/icons/152x152.png",
|
||||
"notification" : "unpackage/res/icons/20x20.png",
|
||||
"notification@2x" : "unpackage/res/icons/40x40.png",
|
||||
"proapp@2x" : "unpackage/res/icons/167x167.png",
|
||||
"settings" : "unpackage/res/icons/29x29.png",
|
||||
"settings@2x" : "unpackage/res/icons/58x58.png",
|
||||
"spotlight" : "unpackage/res/icons/40x40.png",
|
||||
"spotlight@2x" : "unpackage/res/icons/80x80.png"
|
||||
},
|
||||
"iphone" : {
|
||||
"app@2x" : "unpackage/res/icons/120x120.png",
|
||||
"app@3x" : "unpackage/res/icons/180x180.png",
|
||||
"notification@2x" : "unpackage/res/icons/40x40.png",
|
||||
"notification@3x" : "unpackage/res/icons/60x60.png",
|
||||
"settings@2x" : "unpackage/res/icons/58x58.png",
|
||||
"settings@3x" : "unpackage/res/icons/87x87.png",
|
||||
"spotlight@2x" : "unpackage/res/icons/80x80.png",
|
||||
"spotlight@3x" : "unpackage/res/icons/120x120.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"quickapp" : {},
|
||||
"mp-weixin" : {
|
||||
"appid" : "wx1b139d5cf2c91360",
|
||||
"setting" : {
|
||||
"urlCheck" : false
|
||||
},
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-alipay" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-baidu" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"h5" : {
|
||||
"template" : "template.h5.html",
|
||||
"router" : {
|
||||
"mode" : "history",
|
||||
"base" : "/h5/"
|
||||
}
|
||||
}
|
||||
}
|
||||
28
device/pages.json
Normal file
28
device/pages.json
Normal file
@@ -0,0 +1,28 @@
|
||||
// uniapp/pages.json
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "设备信息扫描",
|
||||
"navigationBarBackgroundColor": "#667eea",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "设备管理系统",
|
||||
"navigationBarBackgroundColor": "#F8F8F8",
|
||||
"backgroundColor": "#F8F8F8"
|
||||
},
|
||||
"condition": {
|
||||
"current": 0,
|
||||
"list": [
|
||||
{
|
||||
"name": "设备信息首页",
|
||||
"path": "pages/index/index"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
845
device/pages/index/index.vue
Normal file
845
device/pages/index/index.vue
Normal file
@@ -0,0 +1,845 @@
|
||||
<!-- uniapp/pages/index/index.vue -->
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="header">
|
||||
<text class="title">设备信息扫描</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<view class="info-item">
|
||||
<text class="label">设备唯一标识符(Device ID)</text>
|
||||
<view class="value-row">
|
||||
<text class="value" selectable>{{ deviceInfo.deviceId || '扫描中...' }}</text>
|
||||
<button class="copy-btn" size="mini" @click="copyText(deviceInfo.deviceId)">复制</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Device Info -->
|
||||
<view class="info-item">
|
||||
<text class="label">设备类型</text>
|
||||
<text class="value">{{ deviceInfo.deviceType || '未知' }}</text>
|
||||
</view>
|
||||
|
||||
<view class="info-item">
|
||||
<text class="label">设备品牌</text>
|
||||
<text class="value">{{ deviceInfo.deviceBrand || '未知' }}</text>
|
||||
</view>
|
||||
|
||||
<view class="info-item">
|
||||
<text class="label">设备型号</text>
|
||||
<text class="value">{{ deviceInfo.deviceModel || '未知' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- OS Info -->
|
||||
<view class="info-item">
|
||||
<text class="label">系统名称</text>
|
||||
<text class="value">{{ deviceInfo.osName || '未知' }}</text>
|
||||
</view>
|
||||
|
||||
<view class="info-item">
|
||||
<text class="label">操作系统版本</text>
|
||||
<text class="value">{{ deviceInfo.osVersion || '未知' }}</text>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="info-item">
|
||||
<text class="label">编译器版本</text>
|
||||
<text class="value">{{ deviceInfo.uniCompileVersion || '未知' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- App Info -->
|
||||
<view class="info-item">
|
||||
<text class="label">应用ID</text>
|
||||
<text class="value">{{ deviceInfo.appId || '未知' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- Persistent ID Info -->
|
||||
<view class="info-item">
|
||||
<text class="label">持久化设备ID</text>
|
||||
<view class="value-row">
|
||||
<text class="value" selectable>{{ persistentDeviceId || '未生成' }}</text>
|
||||
<button class="copy-btn" size="mini" @click="copyText(persistentDeviceId)">复制</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- File Status Info -->
|
||||
<view class="info-item">
|
||||
<text class="label">文件路径</text>
|
||||
<text class="value" selectable>{{ filePath || '获取中...' }}</text>
|
||||
</view>
|
||||
|
||||
<view class="info-item">
|
||||
<text class="label">文件状态</text>
|
||||
<text class="value">{{ fileStatus || '检查中...' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 文件操作按钮 -->
|
||||
<view class="button-group">
|
||||
<button class="action-btn primary" @click="checkAndReadFile">检查并读取文件</button>
|
||||
<button class="action-btn secondary" @click="writeFileToDevice">写入文件到设备</button>
|
||||
<button class="action-btn warning" @click="showFilePathInfo">查看文件路径说明</button>
|
||||
</view>
|
||||
|
||||
<view class="tips">
|
||||
<text class="tip-text">提示:文件将保存在设备的公共目录中,应用卸载后文件仍会保留</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
deviceInfo: {},
|
||||
persistentDeviceId: '',
|
||||
fileStatus: '未知',
|
||||
filePath: '未知'
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// 页面加载时自动检查并读取文件
|
||||
this.checkAndReadFile()
|
||||
this.scanDeviceInfo()
|
||||
},
|
||||
methods: {
|
||||
// 检查并读取文件
|
||||
async checkAndReadFile() {
|
||||
try {
|
||||
const result = await this.readFileFromDevice()
|
||||
console.log("读取文件结果:", result);
|
||||
if (result.content) {
|
||||
this.persistentDeviceId = result.content
|
||||
this.filePath = result.path
|
||||
this.fileStatus = '文件存在,内容: ' + result.content
|
||||
uni.showToast({
|
||||
title: '读取文件成功',
|
||||
icon: 'success'
|
||||
})
|
||||
} else {
|
||||
this.filePath = result.path
|
||||
this.fileStatus = '文件不存在,请点击"写入文件到设备"按钮创建文件'
|
||||
uni.showToast({
|
||||
title: '文件不存在',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('读取文件失败:', error)
|
||||
this.fileStatus = '读取文件失败: ' + (error.message || '未知错误')
|
||||
uni.showToast({
|
||||
title: '读取文件失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 从设备读取文件
|
||||
readFileFromDevice() {
|
||||
return new Promise((resolve, reject) => {
|
||||
//#ifdef APP-PLUS
|
||||
// Android平台使用外部公共存储
|
||||
if (plus.os.name === "Android") {
|
||||
// 请求存储权限
|
||||
this.requestStoragePermissions().then(() => {
|
||||
try {
|
||||
// 使用提供的工具函数读取文件
|
||||
const FileUtil = this.getFileUtil();
|
||||
const Environment = plus.android.importClass("android.os.Environment");
|
||||
const externalDir = Environment.getExternalStorageDirectory();
|
||||
const realPath = plus.android.invoke(externalDir, "getAbsolutePath");
|
||||
const filePath = realPath + "/device_id.txt";
|
||||
|
||||
console.log("尝试从路径读取文件: " + filePath);
|
||||
|
||||
// 检查文件是否存在
|
||||
if (FileUtil.isFileExist(filePath)) {
|
||||
// 文件存在,读取内容
|
||||
const contentList = FileUtil.readTxt(filePath, 'utf-8');
|
||||
if (contentList && contentList.length > 0) {
|
||||
resolve({
|
||||
content: contentList[0], // 读取第一行内容
|
||||
path: filePath
|
||||
});
|
||||
} else {
|
||||
resolve({
|
||||
content: '',
|
||||
path: filePath
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 文件不存在
|
||||
resolve({
|
||||
content: '',
|
||||
path: filePath
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('读取文件失败:', e);
|
||||
reject(new Error('读取文件出错: ' + e.message));
|
||||
}
|
||||
}).catch((error) => {
|
||||
reject(new Error('权限请求失败: ' + error.message));
|
||||
});
|
||||
}
|
||||
// iOS平台使用Documents目录(应用卸载后会被删除)
|
||||
else if (plus.os.name === "iOS") {
|
||||
plus.io.requestFileSystem(plus.io.PUBLIC_DOCUMENTS, (fs) => {
|
||||
const filePath = plus.io.convertLocalFileSystemURL(fs.root.toURL() + 'device_id.txt');
|
||||
|
||||
fs.root.getFile('device_id.txt', {create: false}, (fileEntry) => {
|
||||
fileEntry.file((file) => {
|
||||
const reader = new plus.io.FileReader();
|
||||
reader.onloadend = (e) => {
|
||||
resolve({
|
||||
content: e.target.result,
|
||||
path: filePath
|
||||
});
|
||||
};
|
||||
reader.onerror = (e) => {
|
||||
resolve({
|
||||
content: '',
|
||||
path: filePath
|
||||
});
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}, (e) => {
|
||||
resolve({
|
||||
content: '',
|
||||
path: filePath
|
||||
});
|
||||
});
|
||||
}, (e) => {
|
||||
resolve({
|
||||
content: '',
|
||||
path: filePath
|
||||
});
|
||||
});
|
||||
}, (e) => {
|
||||
reject(new Error('无法访问文件系统'));
|
||||
});
|
||||
}
|
||||
//#endif
|
||||
|
||||
//#ifndef APP-PLUS
|
||||
// 非App端使用Storage模拟
|
||||
try {
|
||||
const content = uni.getStorageSync('device_id_file')
|
||||
resolve({
|
||||
content: content || '',
|
||||
path: 'Storage模拟存储'
|
||||
})
|
||||
} catch (e) {
|
||||
resolve({
|
||||
content: '',
|
||||
path: 'Storage模拟存储'
|
||||
})
|
||||
}
|
||||
//#endif
|
||||
})
|
||||
},
|
||||
|
||||
// 写入文件到设备
|
||||
async writeFileToDevice() {
|
||||
try {
|
||||
const result = await this.writeFileToDeviceStorage('787112776')
|
||||
this.filePath = result.path
|
||||
this.fileStatus = '文件已写入: 787112776'
|
||||
this.persistentDeviceId = '787112776'
|
||||
uni.showToast({
|
||||
title: '文件写入成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 显示文件路径提示
|
||||
uni.showModal({
|
||||
title: '文件写入成功',
|
||||
content: `文件已保存到以下路径:\n${result.path}\n\n注意:此文件在应用卸载后仍会保留`,
|
||||
showCancel: false
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('写入文件失败:', error)
|
||||
this.fileStatus = '写入文件失败: ' + (error.message || '未知错误')
|
||||
uni.showToast({
|
||||
title: '写入文件失败',
|
||||
icon: 'none'
|
||||
})
|
||||
|
||||
// 显示详细错误信息
|
||||
uni.showModal({
|
||||
title: '写入失败',
|
||||
content: '错误详情: ' + (error.message || '未知错误'),
|
||||
showCancel: false
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 写入文件到设备存储
|
||||
writeFileToDeviceStorage(content) {
|
||||
return new Promise((resolve, reject) => {
|
||||
//#ifdef APP-PLUS
|
||||
// Android平台使用外部公共存储
|
||||
if (plus.os.name === "Android") {
|
||||
// 请求存储权限
|
||||
this.requestStoragePermissions().then(() => {
|
||||
try {
|
||||
// 使用提供的工具函数写入文件
|
||||
const FileUtil = this.getFileUtil();
|
||||
const Environment = plus.android.importClass("android.os.Environment");
|
||||
const externalDir = Environment.getExternalStorageDirectory();
|
||||
const realPath = plus.android.invoke(externalDir, "getAbsolutePath");
|
||||
const filePath = realPath + "/device_id.txt";
|
||||
|
||||
console.log("尝试写入文件到路径: " + filePath);
|
||||
|
||||
// 确保目录存在
|
||||
const dirPath = realPath;
|
||||
if (FileUtil.mkdirs(dirPath)) {
|
||||
console.log("目录创建成功: " + dirPath);
|
||||
} else {
|
||||
console.log("目录已存在或创建失败: " + dirPath);
|
||||
}
|
||||
|
||||
// 写入文件内容
|
||||
const writeResult = FileUtil.writeTxt(filePath, content, false, 'utf-8');
|
||||
if (writeResult) {
|
||||
console.log("文件写入成功");
|
||||
resolve({
|
||||
path: filePath
|
||||
});
|
||||
} else {
|
||||
console.error("文件写入失败");
|
||||
reject(new Error('文件写入失败'));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('写入文件失败:', e);
|
||||
reject(new Error('写入文件出错: ' + e.message));
|
||||
}
|
||||
}).catch((error) => {
|
||||
reject(new Error('权限请求失败: ' + error.message));
|
||||
});
|
||||
}
|
||||
// iOS平台使用Documents目录
|
||||
else if (plus.os.name === "iOS") {
|
||||
plus.io.requestFileSystem(plus.io.PUBLIC_DOCUMENTS, (fs) => {
|
||||
const filePath = plus.io.convertLocalFileSystemURL(fs.root.toURL() + 'device_id.txt');
|
||||
|
||||
fs.root.getFile('device_id.txt', {create: true}, (fileEntry) => {
|
||||
fileEntry.createWriter((writer) => {
|
||||
writer.onwrite = () => {
|
||||
resolve({
|
||||
path: filePath
|
||||
});
|
||||
};
|
||||
writer.onerror = (e) => {
|
||||
reject(new Error('写入文件出错'));
|
||||
};
|
||||
writer.write(content);
|
||||
}, (e) => {
|
||||
reject(new Error('无法创建文件写入器'));
|
||||
});
|
||||
}, (e) => {
|
||||
reject(new Error('无法创建文件'));
|
||||
});
|
||||
}, (e) => {
|
||||
reject(new Error('无法访问文件系统'));
|
||||
});
|
||||
}
|
||||
//#endif
|
||||
|
||||
//#ifndef APP-PLUS
|
||||
// 非App端使用Storage模拟
|
||||
try {
|
||||
uni.setStorageSync('device_id_file', content)
|
||||
resolve({
|
||||
path: 'Storage模拟存储'
|
||||
})
|
||||
} catch (e) {
|
||||
reject(new Error('存储失败'))
|
||||
}
|
||||
//#endif
|
||||
})
|
||||
},
|
||||
|
||||
// 请求存储权限
|
||||
requestStoragePermissions() {
|
||||
return new Promise((resolve, reject) => {
|
||||
//#ifdef APP-PLUS
|
||||
if (plus.os.name === "Android") {
|
||||
plus.android.requestPermissions([
|
||||
'android.permission.WRITE_EXTERNAL_STORAGE',
|
||||
'android.permission.READ_EXTERNAL_STORAGE'
|
||||
], (resultObj) => {
|
||||
const result = resultObj.granted.length > 0;
|
||||
if (result) {
|
||||
console.log("存储权限获取成功");
|
||||
resolve();
|
||||
} else {
|
||||
console.error("存储权限获取失败");
|
||||
reject(new Error('未获得存储权限'));
|
||||
}
|
||||
}, (error) => {
|
||||
console.error("权限请求出错:", error);
|
||||
reject(new Error('权限请求出错: ' + error.message));
|
||||
});
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
//#endif
|
||||
|
||||
//#ifndef APP-PLUS
|
||||
resolve();
|
||||
//#endif
|
||||
});
|
||||
},
|
||||
|
||||
// 获取文件工具函数
|
||||
getFileUtil() {
|
||||
const FileUtil = {
|
||||
/**
|
||||
* 获取手机内置存储的根路径
|
||||
* @return {String}
|
||||
*/
|
||||
root: function() {
|
||||
const environment = plus.android.importClass("android.os.Environment");
|
||||
return environment.getExternalStorageDirectory();
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建文件
|
||||
* @return {boolean} flase=失败(已存在、操作失败),true=成功
|
||||
*/
|
||||
createNewFile: function(path = '') {
|
||||
const File = plus.android.importClass('java.io.File');
|
||||
let file = new File(path);
|
||||
if (!file.exists()) {
|
||||
return file.createNewFile();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建文件夹
|
||||
* @return {boolean} flase=失败(已存在、操作失败),true=成功
|
||||
*/
|
||||
mkdirs: function(path = ''){
|
||||
const File = plus.android.importClass('java.io.File');
|
||||
let file = new File(path);
|
||||
if (!file.exists()) {
|
||||
return file.mkdirs();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* 读取文件
|
||||
* @param {String} path 文件路径
|
||||
* @param {String} charset 编码
|
||||
* @return {Array<String>} 内容列表(按行读取),文件不存在或异常则返回false
|
||||
*/
|
||||
readTxt: function(path = '', charset = 'utf-8') {
|
||||
const File = plus.android.importClass('java.io.File');
|
||||
const InputStreamReader = plus.android.importClass('java.io.InputStreamReader');
|
||||
const BufferedReader = plus.android.importClass('java.io.BufferedReader');
|
||||
const FileInputStream = plus.android.importClass('java.io.FileInputStream');
|
||||
let file = new File(path);
|
||||
let inputStreamReader = null;
|
||||
let bufferedReader = null;
|
||||
let list = [];
|
||||
try {
|
||||
if (!file.exists()) {
|
||||
return false;
|
||||
}
|
||||
inputStreamReader = new InputStreamReader(new FileInputStream(file), charset);
|
||||
bufferedReader = new BufferedReader(inputStreamReader);
|
||||
let line = '';
|
||||
while (null != (line = bufferedReader.readLine())) {
|
||||
list.push(line);
|
||||
}
|
||||
bufferedReader.close();
|
||||
inputStreamReader.close();
|
||||
} catch (e) {
|
||||
if (null != bufferedReader) {
|
||||
bufferedReader.close();
|
||||
}
|
||||
if (null != inputStreamReader) {
|
||||
inputStreamReader.close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return list;
|
||||
},
|
||||
|
||||
/**
|
||||
* 写入文件内容
|
||||
* @param {String} path 文件路径
|
||||
* @param {String} content 内容
|
||||
* @param {boolean} append 内容写入类型,false=不追加(覆盖原有内容),true=追加(从内容尾部写入)
|
||||
* @param {String} charset 编码
|
||||
* @return {boolean} true=成功,false=失败
|
||||
*/
|
||||
writeTxt: function(path = '', content = '', append = false, charset = 'utf-8') {
|
||||
const File = plus.android.importClass('java.io.File');
|
||||
const FileOutputStream = plus.android.importClass('java.io.FileOutputStream');
|
||||
const OutputStreamWriter = plus.android.importClass('java.io.OutputStreamWriter');
|
||||
|
||||
let outputStreamWriter;
|
||||
let file = new File(path);
|
||||
try {
|
||||
//不存在则创建新的文件
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
outputStreamWriter = new OutputStreamWriter(new FileOutputStream(path, append), charset);
|
||||
outputStreamWriter.write(content);
|
||||
outputStreamWriter.close();
|
||||
} catch (e) {
|
||||
if (null != outputStreamWriter) {
|
||||
outputStreamWriter.close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* 判断文件是否存在
|
||||
* @param path 文件路径
|
||||
* @return true=存在 false=不存在
|
||||
*/
|
||||
isFileExist: function(path = ''){
|
||||
const File = plus.android.importClass('java.io.File');
|
||||
return new File(path).exists()
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
* @param {String} path
|
||||
*/
|
||||
deleteFile: function(path = ''){
|
||||
const File = plus.android.importClass('java.io.File');
|
||||
let file = new File(path);
|
||||
if (file.exists()) {
|
||||
return file.delete();
|
||||
}
|
||||
return false
|
||||
}
|
||||
};
|
||||
|
||||
return FileUtil;
|
||||
},
|
||||
|
||||
// 显示文件路径说明
|
||||
showFilePathInfo() {
|
||||
let content = '';
|
||||
//#ifdef APP-PLUS
|
||||
if (plus.os.name === "Android") {
|
||||
content = 'Android平台:文件保存在设备的公共存储根目录中\n' +
|
||||
'路径类似于:\n' +
|
||||
'/storage/emulated/0/device_id.txt\n\n' +
|
||||
'该文件在应用卸载后仍会保留。';
|
||||
} else if (plus.os.name === "iOS") {
|
||||
content = 'iOS平台:文件保存在应用的Documents目录中\n' +
|
||||
'路径类似于:\n' +
|
||||
'/var/mobile/Containers/Data/Application/应用标识/Documents/device_id.txt\n\n' +
|
||||
'注意:iOS平台应用卸载后文件会被删除,这是系统限制。';
|
||||
}
|
||||
//#endif
|
||||
|
||||
//#ifndef APP-PLUS
|
||||
content = '非App平台使用Storage模拟存储,无法实现持久化保存。';
|
||||
//#endif
|
||||
|
||||
uni.showModal({
|
||||
title: '文件路径说明',
|
||||
content: content,
|
||||
showCancel: false
|
||||
});
|
||||
},
|
||||
|
||||
// 扫描设备信息
|
||||
scanDeviceInfo() {
|
||||
try {
|
||||
// 获取系统信息
|
||||
const systemInfo = uni.getSystemInfoSync()
|
||||
|
||||
// 构建设备信息对象
|
||||
this.deviceInfo = {
|
||||
// Device Info
|
||||
deviceId: this.getRealDeviceId(systemInfo),
|
||||
deviceType: systemInfo.deviceType || '未知',
|
||||
deviceBrand: systemInfo.deviceBrand || '未知',
|
||||
deviceModel: systemInfo.deviceModel || '未知',
|
||||
deviceOrientation: systemInfo.deviceOrientation || '未知',
|
||||
devicePixelRatio: systemInfo.devicePixelRatio || '未知',
|
||||
|
||||
// OS Info
|
||||
osName: systemInfo.osName || systemInfo.platform || '未知',
|
||||
osVersion: systemInfo.osVersion || systemInfo.system || '未知',
|
||||
osLanguage: systemInfo.osLanguage || '未知',
|
||||
osTheme: systemInfo.osTheme || '未知',
|
||||
osAndroidAPILevel: systemInfo.osAndroidAPILevel || '未知',
|
||||
|
||||
// ROM Info
|
||||
romName: systemInfo.romName || '未知',
|
||||
romVersion: systemInfo.romVersion || '未知',
|
||||
|
||||
// Browser Info
|
||||
browserName: systemInfo.browserName || '未知',
|
||||
browserVersion: systemInfo.browserVersion || '未知',
|
||||
|
||||
// Host Info
|
||||
hostName: systemInfo.hostName || '未知',
|
||||
hostVersion: systemInfo.hostVersion || '未知',
|
||||
hostLanguage: systemInfo.hostLanguage || '未知',
|
||||
hostTheme: systemInfo.hostTheme || '未知',
|
||||
hostFontSizeSetting: systemInfo.hostFontSizeSetting || '未知',
|
||||
hostPackageName: systemInfo.hostPackageName || '未知',
|
||||
hostSDKVersion: systemInfo.hostSDKVersion || '未知',
|
||||
|
||||
// Uni-app Framework Info
|
||||
uniPlatform: systemInfo.uniPlatform || '未知',
|
||||
uniCompileVersion: systemInfo.uniCompileVersion || '未知',
|
||||
uniCompilerVersion: systemInfo.uniCompilerVersion || '未知',
|
||||
uniRuntimeVersion: systemInfo.uniRuntimeVersion || '未知',
|
||||
|
||||
// App Info
|
||||
appId: systemInfo.appId || '未知',
|
||||
appName: systemInfo.appName || '未知',
|
||||
appVersion: systemInfo.appVersion || '未知',
|
||||
appVersionCode: systemInfo.appVersionCode || '未知',
|
||||
appWgtVersion: systemInfo.appWgtVersion || '未知',
|
||||
appLanguage: systemInfo.appLanguage || '未知',
|
||||
|
||||
// 兼容旧版本字段
|
||||
brand: systemInfo.brand || '未知',
|
||||
model: systemInfo.model || '未知',
|
||||
system: systemInfo.system || '未知',
|
||||
platform: systemInfo.platform || '未知',
|
||||
screen: `${systemInfo.screenWidth}x${systemInfo.screenHeight}` || '未知'
|
||||
}
|
||||
|
||||
console.log('设备信息扫描完成:', this.deviceInfo)
|
||||
|
||||
uni.showToast({
|
||||
title: '扫描完成',
|
||||
icon: 'success'
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('设备信息扫描失败:', error)
|
||||
uni.showToast({
|
||||
title: '扫描失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 获取真实的设备ID
|
||||
getRealDeviceId(systemInfo) {
|
||||
// 首先尝试从缓存获取deviceId
|
||||
let deviceId = uni.getStorageSync('realDeviceId')
|
||||
|
||||
if (!deviceId) {
|
||||
// 优先使用系统提供的deviceId
|
||||
deviceId = systemInfo.deviceId || systemInfo.uuid || '未知'
|
||||
|
||||
// 如果还是获取不到,尝试其他方式
|
||||
if (!deviceId || deviceId === '未知' || deviceId === '000000000000000') {
|
||||
//#ifdef APP-PLUS
|
||||
try {
|
||||
// App端尝试获取更真实的设备ID
|
||||
const deviceInfo = plus.device.getInfo();
|
||||
if (deviceInfo.uuid && deviceInfo.uuid !== '000000000000000') {
|
||||
deviceId = deviceInfo.uuid;
|
||||
} else if (deviceInfo.imei) {
|
||||
deviceId = deviceInfo.imei;
|
||||
} else if (deviceInfo.imsi) {
|
||||
deviceId = deviceInfo.imsi;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('通过plus.device获取设备ID失败:', e);
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
|
||||
// 如果仍然获取不到,使用持久化ID作为备选
|
||||
if ((!deviceId || deviceId === '未知' || deviceId === '000000000000000') && this.persistentDeviceId) {
|
||||
deviceId = this.persistentDeviceId
|
||||
}
|
||||
|
||||
// 如果仍然获取不到,生成一个备用ID并缓存
|
||||
if (!deviceId || deviceId === '未知' || deviceId === '000000000000000') {
|
||||
deviceId = this.generateFallbackDeviceId(systemInfo)
|
||||
}
|
||||
|
||||
// 将获取到的deviceId保存到缓存中
|
||||
uni.setStorageSync('realDeviceId', deviceId)
|
||||
}
|
||||
|
||||
return deviceId
|
||||
},
|
||||
|
||||
// 备用方案:生成设备ID(仅在无法获取真实ID时使用)
|
||||
generateFallbackDeviceId(systemInfo) {
|
||||
// 基于设备信息和时间戳生成唯一ID
|
||||
const deviceData = `${systemInfo.brand}_${systemInfo.model}_${systemInfo.system}_${systemInfo.platform}_${Date.now()}`
|
||||
|
||||
// 简单的哈希函数生成唯一标识
|
||||
let hash = 0
|
||||
for (let i = 0; i < deviceData.length; i++) {
|
||||
const char = deviceData.charCodeAt(i)
|
||||
hash = ((hash << 5) - hash) + char
|
||||
hash = hash & hash // 转换为32位整数
|
||||
}
|
||||
|
||||
return 'fallback_' + Math.abs(hash).toString(16) + '_' + Date.now()
|
||||
},
|
||||
|
||||
// 复制文本
|
||||
copyText(text) {
|
||||
if (!text) {
|
||||
uni.showToast({
|
||||
title: '无内容可复制',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
uni.setClipboardData({
|
||||
data: text,
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: '已复制',
|
||||
icon: 'success'
|
||||
})
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '复制失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
padding: 40rpx 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
text-shadow: 0 2rpx 4rpx rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.15);
|
||||
backdrop-filter: blur(10rpx);
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 30rpx;
|
||||
padding-bottom: 20rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.info-item:last-child {
|
||||
margin-bottom: 0;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.value-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
word-break: break-all;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
font-size: 24rpx;
|
||||
padding: 10rpx 20rpx;
|
||||
background: #409EFF;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 10rpx;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
padding: 20rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
border: none;
|
||||
border-radius: 50rpx;
|
||||
width: 100%;
|
||||
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.primary {
|
||||
background: linear-gradient(90deg, #ff9a9e 0%, #fecfef 50%, #fecfef 100%);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.warning {
|
||||
background: linear-gradient(90deg, #f6d365 0%, #fda085 100%);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.action-btn:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.tips {
|
||||
padding: 30rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tip-text {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
BIN
device/static/logo.png
Normal file
BIN
device/static/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
13
device/uni.promisify.adaptor.js
Normal file
13
device/uni.promisify.adaptor.js
Normal file
@@ -0,0 +1,13 @@
|
||||
uni.addInterceptor({
|
||||
returnValue (res) {
|
||||
if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
|
||||
return res;
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
res.then((res) => {
|
||||
if (!res) return resolve(res)
|
||||
return res[0] ? reject(res[0]) : resolve(res[1])
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
76
device/uni.scss
Normal file
76
device/uni.scss
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 这里是uni-app内置的常用样式变量
|
||||
*
|
||||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
|
||||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
|
||||
*
|
||||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
|
||||
*/
|
||||
|
||||
/* 颜色变量 */
|
||||
|
||||
/* 行为相关颜色 */
|
||||
$uni-color-primary: #007aff;
|
||||
$uni-color-success: #4cd964;
|
||||
$uni-color-warning: #f0ad4e;
|
||||
$uni-color-error: #dd524d;
|
||||
|
||||
/* 文字基本颜色 */
|
||||
$uni-text-color:#333;//基本色
|
||||
$uni-text-color-inverse:#fff;//反色
|
||||
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
|
||||
$uni-text-color-placeholder: #808080;
|
||||
$uni-text-color-disable:#c0c0c0;
|
||||
|
||||
/* 背景颜色 */
|
||||
$uni-bg-color:#ffffff;
|
||||
$uni-bg-color-grey:#f8f8f8;
|
||||
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
|
||||
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
|
||||
|
||||
/* 边框颜色 */
|
||||
$uni-border-color:#c8c7cc;
|
||||
|
||||
/* 尺寸变量 */
|
||||
|
||||
/* 文字尺寸 */
|
||||
$uni-font-size-sm:12px;
|
||||
$uni-font-size-base:14px;
|
||||
$uni-font-size-lg:16px;
|
||||
|
||||
/* 图片尺寸 */
|
||||
$uni-img-size-sm:20px;
|
||||
$uni-img-size-base:26px;
|
||||
$uni-img-size-lg:40px;
|
||||
|
||||
/* Border Radius */
|
||||
$uni-border-radius-sm: 2px;
|
||||
$uni-border-radius-base: 3px;
|
||||
$uni-border-radius-lg: 6px;
|
||||
$uni-border-radius-circle: 50%;
|
||||
|
||||
/* 水平间距 */
|
||||
$uni-spacing-row-sm: 5px;
|
||||
$uni-spacing-row-base: 10px;
|
||||
$uni-spacing-row-lg: 15px;
|
||||
|
||||
/* 垂直间距 */
|
||||
$uni-spacing-col-sm: 4px;
|
||||
$uni-spacing-col-base: 8px;
|
||||
$uni-spacing-col-lg: 12px;
|
||||
|
||||
/* 透明度 */
|
||||
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
|
||||
|
||||
/* 文章场景相关 */
|
||||
$uni-color-title: #2C405A; // 文章标题颜色
|
||||
$uni-font-size-title:20px;
|
||||
$uni-color-subtitle: #555555; // 二级标题颜色
|
||||
$uni-font-size-subtitle:26px;
|
||||
$uni-color-paragraph: #3F536E; // 文章段落颜色
|
||||
$uni-font-size-paragraph:15px;
|
||||
Reference in New Issue
Block a user