Просмотр исходного кода

Merge branch 'master' of http://1.94.244.160:3000/shuzhihua/pms-app

Zimo 1 неделя назад
Родитель
Сommit
5f590fb039

+ 183 - 185
App.vue

@@ -1,185 +1,183 @@
-<script>
-import { initAppDatabase } from "@/utils/appDb";
-
-export default {
-  onLaunch: (options) => {
-    // #ifdef APP
-    initAppDatabase();
-    // #endif
-
-    console.log("App Launch");
-    console.log(options);
-    // uni.onNetworkStatusChange((event) => {
-    //   console.log(event)
-    // })
-
-    // #ifdef H5
-    // 保存钉钉消息传递的参数,参数可能存在path或query中
-    if (options.query.type) {
-      uni.setStorageSync("dingTalkJson", JSON.stringify(options.query));
-    } else if (options.path && options.path.includes("type")) {
-      const path = options.path;
-      const args = path.split("&");
-      const params = {};
-
-      args.forEach((arg) => {
-        const [key, value] = arg.split("=");
-        if (key && value) {
-          params[key] = value;
-        }
-        console.log(params);
-      });
-      uni.setStorageSync("dingTalkJson", JSON.stringify(params));
-    }
-    // #endif
-
-    // #ifdef APP
-    plus.globalEvent.addEventListener("newintent", () => {
-      const args = plus.runtime.arguments;
-      const parts = args.match(/^deepoil:\/\/([^/]+)\/([^/]+)$/);
-      if (parts) {
-        const type = parts[1];
-        const id = parts[2];
-
-        uni.setStorageSync("dingTalkJson", JSON.stringify({ type, id }));
-        console.log(
-          "App: dingTalkJson -> " + uni.getStorageSync("dingTalkJson")
-        );
-      }
-    });
-    // #endif
-  },
-  onExit: () => {
-    // #ifdef APP
-    // sqlite.closeDB('app')
-    // #endif
-  },
-  onShow: function () {
-    // console.log('App Show')
-  },
-  onHide: function () {
-    // console.log('App Hide')
-  },
-};
-</script>
-
-<style lang="scss">
-/*每个页面公共css */
-@import "./style/common.scss";
-@import "./style/fonts.scss";
-
-/* uniapp组件 样式覆盖  */
-uni-button[type="primary"] {
-  background: #004098 !important;
-}
-
-uni-button[disabled][type="primary"] {
-  background: rgba(0, 64, 152, 0.6) !important;
-}
-uni-button[type="primary"][plain] {
-  color: #004098 !important;
-  border: 1px solid #004098 !important;
-  background-color: transparent !important;
-}
-
-uni-page-body,
-body {
-  width: 100%;
-  height: 100%;
-  box-sizing: border-box;
-  position: relative;
-}
-
-:deep(.uni-tabbar-bottom .uni-tabbar) {
-  box-shadow: 0px -2px 10px 0px rgba(0, 0, 0, 0.1);
-  // padding-top: 9px !important;
-  // padding-bottom: 10px !important;
-  box-sizing: border-box;
-
-  .uni-tabbar__icon {
-    margin-top: 4px;
-  }
-}
-
-.page {
-  position: relative;
-  padding: 20rpx;
-  padding-top: 0;
-  box-sizing: border-box;
-  background: #f3f5f9;
-  width: 100%;
-  height: 100%;
-  font-family: PingFangSC, PingFang SC;
-  overflow: hidden;
-}
-
-.page-nopadding {
-  position: relative;
-  box-sizing: border-box;
-  background: #f3f5f9;
-  width: 100%;
-  height: 100%;
-  font-family: PingFangSC, PingFang SC;
-  overflow: hidden;
-}
-
-.page-back {
-  background-image: url("/static/common/1.png");
-  background-repeat: no-repeat;
-  background-size: 100% 100%;
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 350px;
-  z-index: 0;
-}
-
-.navgator {
-  width: 100%;
-  height: $header-height;
-  line-height: 1;
-  position: fixed;
-  top: $header-top-height;
-  left: 0;
-  background-color: transparent !important;
-  padding-top: calc(7px + env(safe-area-inset-top));
-  box-sizing: border-box;
-  z-index: 22;
-
-  .nav-title {
-    font-family: PingFang-SC, PingFang-SC;
-    font-weight: bold;
-    font-size: 16px;
-    color: #ffffff;
-    line-height: 22px;
-    text-align: right;
-    font-style: normal;
-  }
-
-  .nav-back {
-    width: 40rpx;
-    line-height: 1;
-    position: absolute;
-    left: 20rpx;
-
-    .uni-icons {
-      color: #fff !important;
-    }
-  }
-}
-
-.page-content {
-  position: relative;
-  box-sizing: border-box;
-  width: 100%;
-  height: calc(100% - $header-height - $header-top-height);
-  margin-top: calc($header-height + $header-top-height);
-  overflow: hidden;
-  overflow-y: auto;
-}
-
-.item {
-  box-sizing: border-box;
-}
-</style>
+<script>
+import { initAppDatabase } from '@/utils/appDb';
+
+export default {
+	onLaunch: (options) => {
+		// #ifdef APP
+		initAppDatabase();
+		// #endif
+
+		console.log('App Launch');
+		console.log(options);
+		// uni.onNetworkStatusChange((event) => {
+		//   console.log(event)
+		// })
+
+		// #ifdef H5
+		// 保存钉钉消息传递的参数,参数可能存在path或query中
+		if (options.query.type) {
+			uni.setStorageSync('dingTalkJson', JSON.stringify(options.query));
+		} else if (options.path && options.path.includes('type')) {
+			const path = options.path;
+			const args = path.split('&');
+			const params = {};
+
+			args.forEach((arg) => {
+				const [key, value] = arg.split('=');
+				if (key && value) {
+					params[key] = value;
+				}
+				console.log(params);
+			});
+			uni.setStorageSync('dingTalkJson', JSON.stringify(params));
+		}
+		// #endif
+
+		// #ifdef APP
+		plus.globalEvent.addEventListener('newintent', () => {
+			const args = plus.runtime.arguments;
+			const parts = args.match(/^deepoil:\/\/([^/]+)\/([^/]+)$/);
+			if (parts) {
+				const type = parts[1];
+				const id = parts[2];
+
+				uni.setStorageSync('dingTalkJson', JSON.stringify({ type, id }));
+				console.log('App: dingTalkJson -> ' + uni.getStorageSync('dingTalkJson'));
+			}
+		});
+		// #endif
+	},
+	onExit: () => {
+		// #ifdef APP
+		// sqlite.closeDB('app')
+		// #endif
+	},
+	onShow: function () {
+		// console.log('App Show')
+	},
+	onHide: function () {
+		// console.log('App Hide')
+	}
+};
+</script>
+
+<style lang="scss">
+/*每个页面公共css */
+@import './style/common.scss';
+@import './style/fonts.scss';
+
+/* uniapp组件 样式覆盖  */
+uni-button[type='primary'] {
+	background: #004098 !important;
+}
+
+uni-button[disabled][type='primary'] {
+	background: rgba(0, 64, 152, 0.6) !important;
+}
+uni-button[type='primary'][plain] {
+	color: #004098 !important;
+	border: 1px solid #004098 !important;
+	background-color: transparent !important;
+}
+
+uni-page-body,
+body {
+	width: 100%;
+	height: 100%;
+	box-sizing: border-box;
+	position: relative;
+}
+
+:deep(.uni-tabbar-bottom .uni-tabbar) {
+	box-shadow: 0px -2px 10px 0px rgba(0, 0, 0, 0.1);
+	// padding-top: 9px !important;
+	// padding-bottom: 10px !important;
+	box-sizing: border-box;
+
+	.uni-tabbar__icon {
+		margin-top: 4px;
+	}
+}
+
+.page {
+	position: relative;
+	padding: 20rpx;
+	padding-top: 0;
+	box-sizing: border-box;
+	background: #f3f5f9;
+	width: 100%;
+	height: 100%;
+	font-family: PingFangSC, PingFang SC;
+	overflow: hidden;
+}
+
+.page-nopadding {
+	position: relative;
+	box-sizing: border-box;
+	background: #f3f5f9;
+	width: 100%;
+	height: 100%;
+	font-family: PingFangSC, PingFang SC;
+	overflow: hidden;
+}
+
+.page-back {
+	background-image: url('/static/common/1.png');
+	background-repeat: no-repeat;
+	background-size: 100% 100%;
+	position: fixed;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 350px;
+	z-index: 0;
+}
+
+.navgator {
+	width: 100%;
+	height: $header-height;
+	line-height: 1;
+	position: fixed;
+	top: $header-top-height;
+	left: 0;
+	background-color: transparent !important;
+	padding-top: calc(7px + env(safe-area-inset-top));
+	box-sizing: border-box;
+	z-index: 22;
+
+	.nav-title {
+		font-family: PingFang-SC, PingFang-SC;
+		font-weight: bold;
+		font-size: 16px;
+		color: #ffffff;
+		line-height: 22px;
+		text-align: right;
+		font-style: normal;
+	}
+
+	.nav-back {
+		width: 40rpx;
+		line-height: 1;
+		position: absolute;
+		left: 20rpx;
+
+		.uni-icons {
+			color: #fff !important;
+		}
+	}
+}
+
+.page-content {
+	position: relative;
+	box-sizing: border-box;
+	width: 100%;
+	height: calc(100% - $header-height - $header-top-height);
+	margin-top: calc($header-height + $header-top-height);
+	overflow: hidden;
+	overflow-y: auto;
+}
+
+.item {
+	box-sizing: border-box;
+}
+</style>

+ 1 - 1
android/simpleDemo/src/main/res/values/strings.xml

@@ -1,3 +1,3 @@
 <resources>
-    <string name="app_name">DEEP OIL</string>
+    <string name="app_name">DeepOil</string>
 </resources>

+ 1 - 1
locale/en.json

@@ -13,7 +13,7 @@
 	"index.application-language": "Application Language",
 	"index.language-change-confirm": "Applying this setting will restart the App",
 	"api.message": "Prompt",
-	"app.appName": "DEEP OIL",
+	"app.appName": "DeepOil",
 	"app.home": "Home",
 	"app.user": "Mine",
 	"version.newVersion": "New version found",

+ 1 - 1
locale/ja.json

@@ -13,7 +13,7 @@
 	"index.application-language": "アプリケーション言語",
 	"index.language-change-confirm": "この設定を適用するとアプリが再起動します",
 	"api.message": "ヒント",
-	"app.appName": "DEEP OIL",
+	"app.appName": "DeepOil",
 	"app.home": "ホーム",
 	"app.user": "マイページ",
 	"version.newVersion": "新しいバージョンが見つかりました",

+ 1 - 1
locale/ru.json

@@ -13,7 +13,7 @@
 	"index.application-language": "Язык приложения",
 	"index.language-change-confirm": "Применение этого параметра перезапустит приложение",
 	"api.message": "Подсказка",
-	"app.appName": "DEEP OIL",
+	"app.appName": "DeepOil",
 	"app.home": "Главная",
 	"app.user": "Мой",
 	"version.newVersion": "Найдена новая версия",

+ 1 - 1
locale/zh-Hans.json

@@ -14,7 +14,7 @@
   "index.language-change-confirm": "应用此设置将重启App",
   "api.message": "提示",
   // --------------------------------------- app ----------------------------------------
-  "app.appName": "DEEP OIL",
+  "app.appName": "DeepOil",
   "app.home": "首页",
   "app.user": "我的",
   // --------------------------------------- 版本升级 ----------------------------------------

+ 1 - 1
locale/zh-Hant.json

@@ -14,7 +14,7 @@
 	"index.language-change-confirm": "应用此设置将重启App",
 	"api.message": "提示",
 	// -----------------------------------------------
-	"app.appName": "DEEP OIL",
+	"app.appName": "DeepOil",
 	"app.home": "首页",
 	"app.user": "我的",
 	// ------------------通用-----------------------------

+ 226 - 0
pages/user/agreement.vue

@@ -0,0 +1,226 @@
+<template>
+	<view class="agreement-container">
+		<view class="header">
+			<text class="title">DeepOil用户服务协议</text>
+			<view class="update-info">
+				<text class="update-text">更新日期:2025年12月10日\n生效日期:2025年12月10日</text>
+			</view>
+		</view>
+
+		<view class="content">
+			<view class="section important">
+				<text>
+					【特别提示】请您在开始使用DeepOil之前,认真阅读、充分理解本《用户服务协议》(下称"本协议")的全部内容,特别是涉及您重大权益的加粗、下划线或斜体等显著标识的条款。如您对本协议有任何疑问,请联系客服咨询。如您不同意本协议的任意内容,请立即停止使用本软件及相关服务。您的下载、安装、登录、使用等行为即视为您已阅读并同意接受本协议全部内容的约束。
+				</text>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">一、 协议的范围及确认</text>
+				<view class="paragraph">
+					<text>
+						1.1
+						本协议是您(下称"用户")与山东瑞气能源技术有限公司(下称"我们"或"平台")之间关于下载、安装、使用本软件("DeepOil"),以及使用我们提供的相关服务(下称"服务")所订立的协议。
+					</text>
+				</view>
+				<view class="paragraph">
+					<text>1.2 本协议内容同时包括我们可能不时发布的关于本服务的</text>
+					<text class="bold">相关规则、公告、声明</text>
+					<text>。该等内容一经正式发布,即为本协议不可分割的组成部分,您同样应当遵守。</text>
+				</view>
+				<view class="paragraph">
+					<text>
+						1.3
+						您承诺在开始使用本服务时已是具备完全民事行为能力的自然人、法人或其他组织。若您不具备前述主体资格,请在法定监护人的陪同下阅读并判断是否同意本协议,且您及您的监护人应承担因此导致的一切后果。
+					</text>
+				</view>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">二、 账号注册与使用</text>
+				<view class="paragraph">
+					<text>
+						2.1
+						您可以通过【第三方账号(如钉钉)授权登录】或用户名&密码的方式登陆本平台。您应保证所提供的账号信息真实、准确、完整,并及时更新。因您提供的信息不实导致的任何损失,由您自行承担。
+					</text>
+				</view>
+				<view class="paragraph important">
+					<text>2.2</text>
+					<text class="bold">您的账号仅限于您本人使用,不得以任何形式提供给他人使用,否则我们有权暂停或终止提供服务,并追究您的违约责任。</text>
+				</view>
+				<view class="paragraph">
+					<text>2.3 您有责任妥善保管您的账号及密码/授权凭证,并对以您账号进行的所有活动承担责任。如发现任何未经授权的使用,应立即通知我们。</text>
+				</view>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">三、 服务内容与规范</text>
+				<view class="paragraph">
+					<text>
+						3.1
+						我们通过本软件向您提供【请简述APP核心功能,例如:企业内部办公协同、任务管理、信息查询等服务】。我们有权根据业务发展情况对服务内容进行变更、升级或中断,并将尽可能提前通知。
+					</text>
+				</view>
+				<view class="paragraph">
+					<text>3.2 您在使用服务过程中必须遵守以下规范,</text>
+					<text class="bold">不得从事任何违反法律法规、政策及公序良俗的行为</text>
+					<text>,包括但不限于:</text>
+				</view>
+				<view class="list">
+					<view class="list-item">
+						<text>发布、传播含有违法、反动、色情、暴力、赌博等违反公序良俗的信息;</text>
+					</view>
+					<view class="list-item">
+						<text>侵犯他人知识产权、商业秘密、肖像权、隐私权等合法权益;</text>
+					</view>
+					<view class="list-item">
+						<text>利用技术手段恶意干扰、破坏本服务的正常运行,或进行任何危害网络安全的行为;</text>
+					</view>
+					<view class="list-item">
+						<text>未经授权,使用本服务从事任何商业经营活动(如广告推广)。</text>
+					</view>
+				</view>
+				<view class="paragraph">
+					<text>
+						3.3 如我们发现或收到举报您有违反上述规范的行为,我们有权不经通知随时对相关内容进行删除、屏蔽,并视情节轻重对您的账号采取警告、限制功能、暂停服务、终止服务等措施。
+					</text>
+				</view>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">四、 用户内容与知识产权</text>
+				<view class="paragraph">
+					<text>
+						4.1
+						您在使用服务过程中上传、发布或传输的任何内容(下称"用户内容"),均由您自行承担责任。您应确保对该等内容拥有合法的权利或授权,并同意授予我们一项全球性的、免费的、不可撤销的非独占许可,以便我们能使用、存储、展示、复制、修改用户内容以提供服务。
+					</text>
+				</view>
+				<view class="paragraph important">
+					<text>4.2</text>
+					<text class="bold">本软件(包括但不限于界面设计、源代码、商标、Logo、技术文档)及其服务所包含的所有知识产权均归我们或相关权利人所有。</text>
+					<text>未经我们书面许可,您不得为任何商业或非商业目的自行或许可任何第三方使用。</text>
+				</view>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">五、 免责声明</text>
+				<view class="paragraph important">
+					<text>5.1</text>
+					<text class="bold">我们依照现有技术和条件提供服务,但无法对服务的稳定性、及时性、安全性、准确性作出任何担保。</text>
+					<text>因不可抗力(如网络中断、病毒攻击)、第三方服务故障等原因导致的服务中断或数据丢失,我们在法律允许的范围内免责。</text>
+				</view>
+				<view class="paragraph important">
+					<text>5.2 您理解并同意,</text>
+					<text class="bold">我们仅为用户提供信息存储空间及技术服务,不对用户上传内容的合法性、真实性负责。</text>
+					<text>若第三方对您的内容提出权利主张,您应自行解决并承担全部责任。</text>
+				</view>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">六、 协议的变更与终止</text>
+				<view class="paragraph">
+					<text>6.1 我们有权根据国家法律法规变化及运营需要,修改本协议条款。修改后的协议将在APP内公告公布,</text>
+					<text class="bold">如您不同意修改,有权停止使用服务;如您继续使用,则视为接受修改后的协议。</text>
+				</view>
+				<view class="paragraph">
+					<text>
+						6.2 您有权通过在APP内提交注销申请或发送邮件至指定邮箱的方式终止本协议、注销账号。您注销成功后,我们将停止为您提供服务,并根据适用法律删除或匿名化处理您的个人信息。
+					</text>
+				</view>
+				<view class="paragraph">
+					<text>6.3 如您严重违反本协议,我们有权单方面终止向您提供服务,且无需承担任何责任。</text>
+				</view>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">七、 法律适用与争议解决</text>
+				<view class="paragraph">
+					<text>7.1 本协议的订立、执行、解释及争议的解决均适用中华人民共和国大陆地区法律。</text>
+				</view>
+				<view class="paragraph">
+					<text>7.2 如因本协议发生任何争议,双方应首先友好协商解决;协商不成的,</text>
+					<text class="bold">任何一方均有权将争议提交至山东省东营市东营区南二路233号有管辖权的人民法院诉讼解决。</text>
+				</view>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">八、 其他</text>
+				<view class="paragraph">
+					<text>8.1 本协议条款无论因何种原因部分无效或不可执行,其余条款仍有效,对双方具有约束力。</text>
+				</view>
+				<view class="paragraph">
+					<text>8.2 我们的联系方式:wubj@keruigroup.com。对于用户提出的投诉、举报,我们将按照法律法规及内部政策及时处理。</text>
+				</view>
+			</view>
+
+			<view class="section important">
+				<text>【再次提示】本协议一经更新,将在APP内或网站公布,不另行通知。请您定期查阅以了解最新协议内容。</text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+export default {
+	name: 'Agreement'
+};
+</script>
+
+<style scoped>
+.agreement-container {
+	padding: 30rpx;
+	font-size: 28rpx;
+	line-height: 1.6;
+	color: #333;
+}
+
+.title {
+	font-size: 36rpx;
+	font-weight: bold;
+	text-align: center;
+	display: block;
+	padding-bottom: 20rpx;
+	border-bottom: 2rpx solid #eee;
+}
+
+.update-info {
+	margin: 20rpx 0;
+	text-align: right;
+}
+
+.update-text {
+	color: #666;
+	font-style: italic;
+}
+
+.subtitle {
+	font-size: 32rpx;
+	color: #0056b3;
+	border-left: 8rpx solid #0056b3;
+	padding-left: 20rpx;
+	margin: 30rpx 0 20rpx;
+	display: block;
+}
+
+.paragraph {
+	margin-bottom: 20rpx;
+	text-align: justify;
+}
+
+.list {
+	margin-left: 40rpx;
+	margin-bottom: 20rpx;
+}
+
+.list-item {
+	margin: 10rpx 0;
+}
+
+.bold {
+	font-weight: bold;
+}
+
+.important {
+	color: #d9534f;
+	font-weight: bold;
+}
+</style>

+ 428 - 357
pages/user/login.vue

@@ -1,357 +1,428 @@
-<template>
-  <view class="login">
-    <view class="login-top">
-      <image class="back-img" src="../../static/login/login-back.png"></image>
-      <view class="login-text">
-        <view class="text">
-          {{ $t('login.welcome') }}
-        </view>
-        <view class="text">
-          {{ $t('app.appName') }}
-        </view>
-      </view>
-    </view>
-    <view class="login-form-wrap">
-      <uni-forms class="login-form" ref="formRef" :modelValue="loginData" :rules="loginRules">
-        <uni-forms-item name="username" class="margin-bt">
-          <!-- type="number" -->
-          <uni-easyinput
-            class="login-input"
-            v-model="loginData.username"
-            :placeholder="$t('login.enterUsername')"
-            :placeholderStyle="placeholderStyle"
-            :styles="inputStyles" />
-        </uni-forms-item>
-        <uni-forms-item name="password" class="margin-bt">
-          <uni-easyinput
-            type="password"
-            v-model="loginData.password"
-            :placeholder="$t('login.enterPassword')"
-            :placeholderStyle="placeholderStyle"
-            :styles="inputStyles" />
-        </uni-forms-item>
-      </uni-forms>
-      <button type="primary" @click="formSubmit(formRef)">
-        {{ $t('login.login') }}
-      </button>
-      <view class="flex-row align-center justify-between">
-        <view class="btn-text" @click="loginWithDingTalk">
-          {{ $t('login.loginWithDingTalk') }}
-        </view>
-        <view class="btn-text" @click="openLanguagePopup">
-          {{ $t('login.languageChange') }}
-        </view>
-      </view>
-    </view>
-
-    <!-- 引用语言选择组件 -->
-    <language-popup ref="languagePopupRef" />
-    <upgrade ref="upgradeRef" />
-  </view>
-</template>
-
-<script setup>
-  import { reactive, ref, onMounted, nextTick, getCurrentInstance } from 'vue';
-  import { onLoad } from '@dcloudio/uni-app';
-  // 引入接口api
-  import { appLogin, dingTalkLogin, dingTalkLoginH5, getInfo, getTokenByUserId } from '@/api/login.js';
-  // 引入配置文件
-  import config from '@/utils/config';
-  // 引入数据库操作
-  import { saveUser } from '@/utils/appDb';
-  // 引入本地存储操作
-  import { setUserId, setToken, setDeptId, setUserInfo } from '@/utils/auth.js';
-  // 引入组件
-  import Upgrade from '@/components/upgrade.vue';
-  import LanguagePopup from '@/components/language-popup.vue';
-  // 引入钉钉JSAPI -- 仅在H5环境下使用
-  let dd = null;
-  // #ifdef H5
-  import * as dingTalkJsApi from 'dingtalk-jsapi';
-  dd = dingTalkJsApi;
-  // #endif
-
-  const { appContext } = getCurrentInstance();
-  const t = appContext.config.globalProperties.$t;
-  const languagePopupRef = ref(null);
-
-  const openLanguagePopup = () => {
-    languagePopupRef.value.open();
-  };
-
-  // 判断当前环境是否在钉钉环境
-  const isDingTalk = () => {
-    const ua = window.navigator.userAgent.toLowerCase();
-    console.log('🚀 ~ 当前环境 ~ ua:', ua);
-    return ua.includes('dingtalk') || ua.includes('dingtalkwork');
-  };
-
-  const dingTalkAutoLogin = async () => {
-    // 判断是否在钉钉环境
-    if (!isDingTalk()) {
-      console.log('当前环境不是钉钉环境,无法自动登录');
-      return;
-    }
-    // 执行钉钉微应用免登逻辑
-    loginWithDingTalkH5();
-  };
-
-  // 钉钉登录
-  const loginWithDingTalk = async () => {
-    // #ifdef APP
-    const plugin = uni.requireNativePlugin('DingTalk');
-    // 钉钉登录,这里无法使用async,否则java端会报参数错误
-    plugin.login(res => {
-      console.log(res);
-      if (res.success === 1) {
-        dingTalkLogin({
-          type: 20,
-          code: res.code,
-          state: res.state,
-        }).then(res => {
-          console.log(res);
-          handleLoginSuccess(res);
-        });
-      } else if (res.success === 2) {
-        uni.showToast({ title: t('login.dingTalkError'), icon: 'none' });
-        console.error('APP端钉钉登录失败:', res);
-      }
-    });
-    // #endif
-
-    // #ifdef H5
-    if (isDingTalk()) {
-      if (!dd) {
-        uni.showToast({ title: t('login.dingTalkJsapiMissing'), icon: 'none' });
-        return;
-      }
-      loginWithDingTalkH5();
-    } else {
-      console.log('当前是普通 H5 环境,无法使用钉钉登录');
-      uni.showToast({ title: t('login.h5DingTalk'), icon: 'none' });
-    }
-    // #endif
-  };
-
-  const loginWithDingTalkH5 = async () => {
-    const corpId = config.default.corpId;
-    console.log('🚀 ~ loginWithDingTalkH5 ~ corpId:', corpId);
-    const clientId = config.default.clientId;
-    console.log('🚀 ~ loginWithDingTalkH5 ~ clientId:', clientId);
-
-    if (!corpId || !clientId) {
-      console.error('缺少必要参数');
-      return;
-    }
-    dd.requestAuthCode({
-      corpId,
-      clientId,
-      success: async result => {
-        console.log('🚀 ~ loginWithDingTalkH5 ~ result:', result);
-        const { code } = result;
-        dingTalkLoginH5({
-          type: 10,
-          state: new Date().getTime(),
-          code: code,
-        })
-          .then(res => {
-            console.log('🚀 ~ loginWithDingTalkH5 ~ res:', res);
-            handleLoginSuccess(res);
-          })
-          .catch(err => {
-            console.log('🚀 ~ loginWithDingTalkH5 ~ err:', err);
-          });
-      },
-      fail: err => {
-        console.log('🚀 ~ loginWithDingTalkH5 ~ err:', err);
-        uni.showToast({
-          title: '获取code失败:' + JSON.stringify(err),
-          icon: 'none',
-        });
-      },
-    });
-  };
-
-  onLoad(async options => {
-    console.log('onLoad Login', uni.getLocale(), 11, uni.getStorageSync('language'));
-
-    console.log(options);
-
-    // 保存钉钉消息传递的参数
-    if (options.userId) {
-      uni.setStorageSync('dingTalkJson', JSON.stringify(options));
-      const isLoggedIn = uni.getStorageSync('userId');
-      if (!isLoggedIn) {
-        const result = await getTokenByUserId(options.userId);
-        await handleLoginSuccess(result);
-      }
-    }
-    // #ifdef H5
-    // 当前环境为H5时,判断是否是通过钉钉微应用打开的链接
-    // 获取当前Url地址
-    const url = window.location.href;
-    console.log('当前环境为H5时 当前Url地址:', url);
-    // 判断是否是通过钉钉微应用打开的链接
-    if (url.includes('/deepoil')) {
-      dingTalkAutoLogin();
-    }
-    // #endif
-  });
-
-  onMounted(() => {
-    // console.log("onMounted");
-    // 检查是否需要显示语言选择弹窗
-    if (!uni.getStorageSync('language')) {
-      nextTick(() => {
-        openLanguagePopup();
-      });
-    }
-    // 检查是否已登录
-    const isLoggedIn = uni.getStorageSync('userId');
-    // console.log("isLoggedIn", isLoggedIn);
-    if (isLoggedIn) {
-      uni.switchTab({
-        url: '/pages/home/index',
-      });
-    }
-  });
-
-  const placeholderStyle = ref('color:#797979;font-weight:500;font-size:16px');
-  const inputStyles = reactive({
-    backgroundColor: '#F0F3FB',
-    color: '#797979',
-  });
-  const loginData = reactive({
-    username: '',
-    password: '',
-  });
-  const loginRules = ref({
-    username: {
-      rules: [
-        {
-          required: true,
-          errorMessage: t('login.enterUsername'),
-        },
-      ],
-    },
-    password: {
-      rules: [
-        {
-          required: true,
-          errorMessage: t('login.enterPassword'),
-        },
-      ],
-    },
-  });
-
-  const formRef = ref();
-  const formSubmit = async formEl => {
-    if (!formEl) return;
-    await formEl
-      .validate()
-      .then(res => {
-        appLogin({
-          ...loginData,
-          // rememberMe: ,
-          // tenantName: ""
-        })
-          .then(async result => {
-            console.log('result,', result.data);
-            if (result) {
-              await saveUser({
-                name: loginData.username,
-                pwd: loginData.password,
-              });
-              await handleLoginSuccess(result);
-            }
-          })
-          .finally(() => {});
-      })
-      .catch(err => {
-        console.log('err', err);
-      });
-  };
-
-  const handleLoginSuccess = async result => {
-    if (result) {
-      await setUserId(result.data.userId);
-      await setToken(result.data);
-      await getInfo().then(async res => {
-        // console.log('useres', res)
-        const data = JSON.stringify({
-          user: res.data.user,
-          roles: res.data.roles,
-        });
-        // console.log('data', data)
-        await setUserInfo(data);
-        await setDeptId(res.data.user.deptId);
-
-        await uni.switchTab({
-          url: '/pages/home/index',
-        });
-      });
-    }
-  };
-</script>
-
-<style lang="scss" scoped>
-  .login-top {
-    position: relative;
-    width: 100%;
-    height: 422rpx;
-  }
-
-  .back-img {
-    width: 100%;
-    height: 100%;
-  }
-
-  .login-text {
-    width: 100%;
-    height: 100%;
-    box-sizing: border-box;
-    position: absolute;
-    top: 0;
-    left: 0;
-    color: #ffffff;
-    font-size: 40rpx;
-    font-family: 'Negreta,PingFang SC';
-    font-weight: 600;
-    padding: 0 56rpx;
-    display: flex;
-    justify-content: center;
-    flex-direction: column;
-
-    .text {
-      width: 100%;
-      margin-bottom: 6rpx;
-    }
-  }
-
-  .margin-bt {
-    margin-bottom: 25px;
-  }
-
-  .login-form-wrap {
-    padding: 60rpx;
-  }
-
-  :deep(.uni-easyinput__content-input) {
-    height: 45px;
-  }
-
-  :deep(.uni-input-input) {
-    color: #999999 !important;
-  }
-
-  uni-button[type='primary'] {
-    background: #004098;
-  }
-
-  .btn-text {
-    color: #004098;
-    margin-top: 20px;
-    font-size: 14px;
-    font-weight: 500;
-  }
-</style>
+<template>
+	<view class="login">
+		<view class="login-top">
+			<image class="back-img" src="../../static/login/login-back.png"></image>
+			<view class="login-text">
+				<view class="text">
+					{{ $t('login.welcome') }}
+				</view>
+				<view class="text">
+					{{ $t('app.appName') }}
+				</view>
+			</view>
+		</view>
+		<view class="login-form-wrap">
+			<uni-forms class="login-form" ref="formRef" :modelValue="loginData" :rules="loginRules">
+				<uni-forms-item name="username" class="margin-bt">
+					<!-- type="number" -->
+					<uni-easyinput class="login-input" v-model="loginData.username" :placeholder="$t('login.enterUsername')" :placeholderStyle="placeholderStyle" :styles="inputStyles" />
+				</uni-forms-item>
+				<uni-forms-item name="password" class="margin-bt">
+					<uni-easyinput type="password" v-model="loginData.password" :placeholder="$t('login.enterPassword')" :placeholderStyle="placeholderStyle" :styles="inputStyles" />
+				</uni-forms-item>
+			</uni-forms>
+			<button type="primary" @click="formSubmit(formRef)">
+				{{ $t('login.login') }}
+			</button>
+			<view class="flex-row align-center justify-between">
+				<view class="btn-text" @click="loginWithDingTalk">
+					{{ $t('login.loginWithDingTalk') }}
+				</view>
+				<view class="btn-text" @click="openLanguagePopup">
+					{{ $t('login.languageChange') }}
+				</view>
+			</view>
+		</view>
+
+		<view class="uni-padding-wrap">
+			<view>
+				<checkbox-group @change="handleChange">
+					<label>
+						<checkbox :value="true" :checked="isChecked" style="transform: scale(0.6)" />
+					</label>
+				</checkbox-group>
+			</view>
+
+			<view class="uni-title">
+				已阅读并同意
+				<text style="text-decoration: underline" @click="goPrivacy">《隐私政策》</text>
+
+				和
+				<text style="text-decoration: underline" @click="goAgreement">《用户服务协议》</text>
+			</view>
+
+			<uni-popup ref="privacyRef">
+				<scroll-view scroll-y="true" class="privacy" style="height: 500px; border-radius: 20rpx">
+					<view style="background-color: #fff; padding: 0 50rpx; border-radius: 20rpx">
+						<Privacy />
+					</view>
+				</scroll-view>
+			</uni-popup>
+
+			<uni-popup ref="aggRef">
+				<scroll-view scroll-y="true" class="privacy" style="height: 500px; border-radius: 20rpx">
+					<view style="background-color: #fff; padding: 0 50rpx; border-radius: 20rpx">
+						<Agg />
+					</view>
+				</scroll-view>
+			</uni-popup>
+		</view>
+
+		<!-- 引用语言选择组件 -->
+		<language-popup ref="languagePopupRef" />
+		<upgrade ref="upgradeRef" />
+	</view>
+</template>
+
+<script setup>
+import { reactive, ref, onMounted, nextTick, getCurrentInstance } from 'vue';
+import { onLoad } from '@dcloudio/uni-app';
+// 引入接口api
+import { appLogin, dingTalkLogin, dingTalkLoginH5, getInfo, getTokenByUserId } from '@/api/login.js';
+// 引入配置文件
+import config from '@/utils/config';
+// 引入数据库操作
+import { saveUser } from '@/utils/appDb';
+// 引入本地存储操作
+import { setUserId, setToken, setDeptId, setUserInfo } from '@/utils/auth.js';
+// 引入组件
+import Upgrade from '@/components/upgrade.vue';
+import LanguagePopup from '@/components/language-popup.vue';
+import Privacy from './privacy.vue';
+import Agg from './agreement.vue';
+
+// 引入钉钉JSAPI -- 仅在H5环境下使用
+let dd = null;
+// #ifdef H5
+import * as dingTalkJsApi from 'dingtalk-jsapi';
+dd = dingTalkJsApi;
+// #endif
+
+const { appContext } = getCurrentInstance();
+const t = appContext.config.globalProperties.$t;
+const languagePopupRef = ref(null);
+
+const openLanguagePopup = () => {
+	languagePopupRef.value.open();
+};
+
+let isChecked = ref(false);
+let my_value = ref(false);
+
+const handleChange = (val) => {
+	my_value.value = val.detail.value[0];
+};
+
+let privacyRef = ref(null);
+let aggRef = ref(null);
+
+const goPrivacy = () => {
+	privacyRef.value.open();
+};
+
+const goAgreement = () => {
+	aggRef.value.open();
+};
+
+// 判断当前环境是否在钉钉环境
+const isDingTalk = () => {
+	const ua = window.navigator.userAgent.toLowerCase();
+	console.log('🚀 ~ 当前环境 ~ ua:', ua);
+	return ua.includes('dingtalk') || ua.includes('dingtalkwork');
+};
+
+const dingTalkAutoLogin = async () => {
+	// 判断是否在钉钉环境
+	if (!isDingTalk()) {
+		console.log('当前环境不是钉钉环境,无法自动登录');
+		return;
+	}
+	// 执行钉钉微应用免登逻辑
+	loginWithDingTalkH5();
+};
+
+// 钉钉登录
+const loginWithDingTalk = async () => {
+	// #ifdef APP
+	const plugin = uni.requireNativePlugin('DingTalk');
+	// 钉钉登录,这里无法使用async,否则java端会报参数错误
+	plugin.login((res) => {
+		console.log(res);
+		if (res.success === 1) {
+			dingTalkLogin({
+				type: 20,
+				code: res.code,
+				state: res.state
+			}).then((res) => {
+				console.log(res);
+				handleLoginSuccess(res);
+			});
+		} else if (res.success === 2) {
+			uni.showToast({ title: t('login.dingTalkError'), icon: 'none' });
+			console.error('APP端钉钉登录失败:', res);
+		}
+	});
+	// #endif
+
+	// #ifdef H5
+	if (isDingTalk()) {
+		if (!dd) {
+			uni.showToast({ title: t('login.dingTalkJsapiMissing'), icon: 'none' });
+			return;
+		}
+		loginWithDingTalkH5();
+	} else {
+		console.log('当前是普通 H5 环境,无法使用钉钉登录');
+		uni.showToast({ title: t('login.h5DingTalk'), icon: 'none' });
+	}
+	// #endif
+};
+
+const loginWithDingTalkH5 = async () => {
+	const corpId = config.default.corpId;
+	console.log('🚀 ~ loginWithDingTalkH5 ~ corpId:', corpId);
+	const clientId = config.default.clientId;
+	console.log('🚀 ~ loginWithDingTalkH5 ~ clientId:', clientId);
+
+	if (!corpId || !clientId) {
+		console.error('缺少必要参数');
+		return;
+	}
+	dd.requestAuthCode({
+		corpId,
+		clientId,
+		success: async (result) => {
+			console.log('🚀 ~ loginWithDingTalkH5 ~ result:', result);
+			const { code } = result;
+			dingTalkLoginH5({
+				type: 10,
+				state: new Date().getTime(),
+				code: code
+			})
+				.then((res) => {
+					console.log('🚀 ~ loginWithDingTalkH5 ~ res:', res);
+					handleLoginSuccess(res);
+				})
+				.catch((err) => {
+					console.log('🚀 ~ loginWithDingTalkH5 ~ err:', err);
+				});
+		},
+		fail: (err) => {
+			console.log('🚀 ~ loginWithDingTalkH5 ~ err:', err);
+			uni.showToast({
+				title: '获取code失败:' + JSON.stringify(err),
+				icon: 'none'
+			});
+		}
+	});
+};
+
+onLoad(async (options) => {
+	console.log('onLoad Login', uni.getLocale(), 11, uni.getStorageSync('language'));
+
+	console.log(options);
+
+	// 保存钉钉消息传递的参数
+	if (options.userId) {
+		uni.setStorageSync('dingTalkJson', JSON.stringify(options));
+		const isLoggedIn = uni.getStorageSync('userId');
+		if (!isLoggedIn) {
+			const result = await getTokenByUserId(options.userId);
+			await handleLoginSuccess(result);
+		}
+	}
+	// #ifdef H5
+	// 当前环境为H5时,判断是否是通过钉钉微应用打开的链接
+	// 获取当前Url地址
+	const url = window.location.href;
+	console.log('当前环境为H5时 当前Url地址:', url);
+	// 判断是否是通过钉钉微应用打开的链接
+	if (url.includes('/deepoil')) {
+		dingTalkAutoLogin();
+	}
+	// #endif
+});
+
+onMounted(() => {
+	// console.log("onMounted");
+	// 检查是否需要显示语言选择弹窗
+	if (!uni.getStorageSync('language')) {
+		nextTick(() => {
+			openLanguagePopup();
+		});
+	}
+	// 检查是否已登录
+	const isLoggedIn = uni.getStorageSync('userId');
+	// console.log("isLoggedIn", isLoggedIn);
+	if (isLoggedIn) {
+		uni.switchTab({
+			url: '/pages/home/index'
+		});
+	}
+});
+
+const placeholderStyle = ref('color:#797979;font-weight:500;font-size:16px');
+const inputStyles = reactive({
+	backgroundColor: '#F0F3FB',
+	color: '#797979'
+});
+const loginData = reactive({
+	username: '',
+	password: ''
+});
+const loginRules = ref({
+	username: {
+		rules: [
+			{
+				required: true,
+				errorMessage: t('login.enterUsername')
+			}
+		]
+	},
+	password: {
+		rules: [
+			{
+				required: true,
+				errorMessage: t('login.enterPassword')
+			}
+		]
+	}
+});
+
+const formRef = ref();
+const formSubmit = async (formEl) => {
+	if (!my_value.value) {
+		uni.showToast({
+			title: '请阅读并同意隐私政策和用户服务协议',
+			icon: 'none', // 可选 success/error/loading/none
+			duration: 2000, // 持续时间,单位ms
+			mask: true // 是否显示透明蒙层,防止触摸穿透
+		});
+
+		return;
+	}
+	if (!formEl) return;
+	await formEl
+		.validate()
+		.then((res) => {
+			appLogin({
+				...loginData
+				// rememberMe: ,
+				// tenantName: ""
+			})
+				.then(async (result) => {
+					console.log('result,', result.data);
+					if (result) {
+						await saveUser({
+							name: loginData.username,
+							pwd: loginData.password
+						});
+						await handleLoginSuccess(result);
+					}
+				})
+				.finally(() => {});
+		})
+		.catch((err) => {
+			console.log('err', err);
+		});
+};
+
+const handleLoginSuccess = async (result) => {
+	if (result) {
+		await setUserId(result.data.userId);
+		await setToken(result.data);
+		await getInfo().then(async (res) => {
+			// console.log('useres', res)
+			const data = JSON.stringify({
+				user: res.data.user,
+				roles: res.data.roles
+			});
+			// console.log('data', data)
+			await setUserInfo(data);
+			await setDeptId(res.data.user.deptId);
+
+			await uni.switchTab({
+				url: '/pages/home/index'
+			});
+		});
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+.privacy {
+	height: 60vh;
+	width: 85vw;
+	overflow: hidden;
+}
+
+.uni-padding-wrap {
+	display: flex;
+	z-index: 999;
+	justify-content: center;
+	align-items: center;
+	padding: 0 10rpx;
+}
+.uni-title {
+	font-size: 12px;
+}
+.login-top {
+	position: relative;
+	width: 100%;
+	height: 422rpx;
+}
+
+.back-img {
+	width: 100%;
+	height: 100%;
+}
+
+.login-text {
+	width: 100%;
+	height: 100%;
+	box-sizing: border-box;
+	position: absolute;
+	top: 0;
+	left: 0;
+	color: #ffffff;
+	font-size: 40rpx;
+	font-family: 'Negreta,PingFang SC';
+	font-weight: 600;
+	padding: 0 56rpx;
+	display: flex;
+	justify-content: center;
+	flex-direction: column;
+
+	.text {
+		width: 100%;
+		margin-bottom: 6rpx;
+	}
+}
+
+.margin-bt {
+	margin-bottom: 25px;
+}
+
+.login-form-wrap {
+	padding: 60rpx;
+}
+
+:deep(.uni-easyinput__content-input) {
+	height: 45px;
+}
+
+:deep(.uni-input-input) {
+	color: #999999 !important;
+}
+
+uni-button[type='primary'] {
+	background: #004098;
+}
+
+.btn-text {
+	color: #004098;
+	margin-top: 20px;
+	font-size: 14px;
+	font-weight: 500;
+}
+</style>

+ 272 - 0
pages/user/privacy.vue

@@ -0,0 +1,272 @@
+<template>
+	<view class="privacy-container">
+		<view class="header">
+			<text class="title">DeepOil 隐私政策</text>
+			<view class="update-info">
+				<text class="update-text">更新日期:2025年12月10日\n生效日期:2025年12月10日</text>
+			</view>
+			<view class="publisher">
+				<text>发布主体:山东瑞气能源技术有限公司(统一社会信用代码:91370502MA3FBXDRXU;联系邮箱:wubj@keruigroup.com;注册地址:山东省东营市东营区南二路233号)</text>
+			</view>
+		</view>
+
+		<view class="content">
+			<view class="section">
+				<text>
+					欢迎使用DeepOil!我们深知个人信息对您的重要性,并庄严承诺保护您的隐私安全。本政策旨在清晰说明在您使用我们的产品与服务时,我们如何收集、使用、存储、共享和保护您的个人信息,以及您享有何种权利。
+				</text>
+			</view>
+
+			<view class="section">
+				<text class="bold">请您在使用前,仔细阅读并理解本政策的全部内容。当您开始使用或继续使用我们的服务,即表示您已完全同意本政策的内容。如您有任何疑问,请联系我们。</text>
+			</view>
+
+			<view class="section">
+				<text>
+					我们的产品基于DCloud uni-app(5+ App/Wap2App)开发,应用运行期间需要收集您的设备唯一识别码(IMEI/android ID/DEVICE_ID/IDFA、SIM 卡 IMSI
+					信息、OAID)以提供统计分析服务,并通过应用启动数据及异常错误日志分析改进性能和用户体验,为用户提供更好的服务。
+				</text>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">一、 我们如何收集和使用您的个人信息</text>
+				<text>我们仅会出于本政策所述的以下目的,收集和使用您的个人信息:</text>
+
+				<view class="list">
+					<view class="list-item">
+						<text class="bold">账号注册与登录</text>
+						<text>:当您通过【第三方登录方式,如:钉钉】创建账号时,我们会从该第三方处获取您授权的</text>
+						<text class="bold">头像、昵称、唯一标识符</text>
+						<text>,用于为您生成账户。</text>
+					</view>
+
+					<view class="list-item">
+						<text class="bold">为实现功能所必需的第三方服务提供商</text>
+						<text>
+							:为了保障产品功能与服务的稳定实现,我们的应用中嵌入了由第三方提供的软件工具开发包(SDK)。这些SDK会基于其隐私政策收集和使用您的部分信息。我们会对合作伙伴获取信息的SDK进行严格的安全评估,并与其签订数据保护协议,要求其严格遵守相关法律法规与合规要求。我们接入的第三方SDK主要服务于以下功能和目的:
+						</text>
+
+						<view class="sub-list">
+							<view class="sub-list-item">
+								<text class="bold">钉钉登录SDK(Android)</text>
+
+								<text>提供方:钉钉科技有限公司\n</text>
+								<text>使用目的:用于支持您通过钉钉账号登录本应用。\n</text>
+								<text>包名:com.android.dingtalk.openauth\n</text>
+								<text>收集个人信息类型:设备标识信息、应用信息。\n</text>
+								<view class="link" @click="openDingTalkPolicy">
+									<text>《钉钉开放平台隐私政策》</text>
+								</view>
+							</view>
+						</view>
+					</view>
+
+					<view class="list-item">
+						<text class="bold">保障产品正常运行与安全</text>
+						<text>:当您使用APP时,为保障基础服务安全稳定运行,我们会</text>
+						<text class="bold">自动收集</text>
+						<text>您的设备信息(</text>
+						<text class="bold">设备型号、操作系统版本、唯一设备标识符(如Android ID/IDFA)、网络设备硬件地址(MAC)</text>
+						<text>)、日志信息(</text>
+						<text class="bold">操作时间、访问服务类型</text>
+						<text>)及应用列表(用于识别是否为恶意应用环境)。</text>
+						<text class="bold">请注意,此类信息在您同意本政策前不会收集。</text>
+					</view>
+
+					<view class="list-item">
+						<text class="bold">实现特定业务功能</text>
+						:
+						<view class="sub-list">
+							<view class="sub-list-item">
+								<text>为了您能上传图片,我们会请求您授权</text>
+								<text class="bold">相机/相册</text>
+								<text>权限,相关图片仅用于您所选功能,不会私自读取。</text>
+							</view>
+						</view>
+					</view>
+
+					<view class="list-item">
+						<text class="bold">其他</text>
+						<text>:当我们要将信息用于本政策未载明的其他用途时,会事先再次征求您的同意。</text>
+					</view>
+				</view>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">二、 我们如何使用Cookie和同类技术</text>
+				<text>
+					我们或我们的第三方合作伙伴(如数据分析服务商)可能会使用Cookie和网络信标来记录您的偏好,分析产品使用情况。您可以通过浏览器设置管理Cookie,但这可能会影响部分功能体验。
+				</text>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">三、 我们如何共享、转让、公开披露您的个人信息</text>
+				<text class="bold">我们不会将您的个人信息出售给任何第三方。</text>
+				<text>仅在以下必要情况下,我们可能会共享信息:</text>
+
+				<view class="list">
+					<view class="list-item">
+						<text class="bold">获得您的明确同意后</text>
+						<text>。</text>
+					</view>
+					<view class="list-item">
+						<text class="bold">为实现功能所必需的第三方服务提供商</text>
+						<text>:为实现【钉钉登录】功能,我们会将必要的登录请求信息提供给</text>
+						<text class="bold">钉钉开放平台</text>
+						<text>我们已与这些合作伙伴签署严格的保密协议,要求其按照我们的指示、本政策以及其他任何相关的保密和安全措施来处理个人信息。</text>
+					</view>
+					<view class="list-item">
+						<text class="bold">法律与监管要求</text>
+						<text>:根据法律法规规定、诉讼争议解决需要,或按行政、司法机关依法提出的要求。</text>
+					</view>
+				</view>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">四、 我们如何存储和保护您的个人信息</text>
+				<view class="list">
+					<view class="list-item">
+						<text class="bold">存储地点</text>
+						<text>:原则上,我们在中华人民共和国境内收集和产生的个人信息,将存储在境内。</text>
+					</view>
+					<view class="list-item">
+						<text class="bold">安全措施</text>
+						<text>:我们采取包括加密传输、访问控制、安全审计等合理可行的措施保护您的信息。尽管已尽力防护,但请注意,没有任何安全措施是百分百完美的。</text>
+					</view>
+				</view>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">五、 您的权利</text>
+				<text>您有权:</text>
+				<view class="list">
+					<view class="list-item">
+						<text class="bold">访问、更正、删除</text>
+						<text>您的个人信息(通常在APP"我的-设置-账号与安全"中操作);</text>
+					</view>
+					<view class="list-item">
+						<text class="bold">撤回已同意的授权</text>
+						<text>(可通过设备系统设置关闭相应权限);</text>
+					</view>
+					<view class="list-item">
+						<text class="bold">注销账号</text>
+						<text>(可通过APP内指定流程或联系我们处理);</text>
+					</view>
+					<view class="list-item">
+						<text class="bold">投诉举报</text>
+						<text>。如果您认为我们的处理损害了您的权益,可以通过本政策末尾的联系方式与我们联系,或向相关监管部门投诉。</text>
+					</view>
+				</view>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">六、 我们如何处理未成年人的个人信息</text>
+				<text>
+					我们的产品与服务主要面向成年人。如果您是未满14周岁的未成年人,请在父母或监护人的指导下使用。如果我们发现自己在未获得监护人同意的情况下收集了未成年人的个人信息,会设法尽快删除相关数据。
+				</text>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">七、 本政策如何更新</text>
+				<text>我们可能适时修订本政策。更新后,我们会通过在APP内显著位置提示、推送通知等方式提醒您。更新后的政策自发布之日起生效。请您定期查阅以了解最新隐私保护内容。</text>
+			</view>
+
+			<view class="section">
+				<text class="subtitle">八、 如何联系我们</text>
+				<text>如您对本政策或您的个人信息处理有任何疑问、意见或建议,请通过以下方式与我们联系:</text>
+				<view class="contact-info">
+					<text class="bold">公司名称</text>
+					<text>:山东瑞气能源技术有限公司\n</text>
+					<text class="bold">电子邮箱</text>
+					<text>:wubj@keruigroup.com</text>
+				</view>
+				<text>我们将尽快审核所涉问题,并在【15】个工作日内予以回复。</text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+export default {
+	methods: {
+		openDingTalkPolicy() {
+			// #ifdef H5
+			window.open('https://open.dingtalk.com/document/residential/privacy-policy', '_blank');
+			// #endif
+
+			// #ifndef H5
+			plus.runtime.openURL('https://open.dingtalk.com/document/residential/privacy-policy');
+			// #endif
+		}
+	}
+};
+</script>
+
+<style scoped>
+.privacy-container {
+	padding: 30rpx;
+	font-size: 28rpx;
+	line-height: 1.6;
+	color: #333;
+}
+
+.title {
+	font-size: 36rpx;
+	font-weight: bold;
+}
+
+.update-info {
+	margin: 20rpx 0;
+}
+
+.update-text {
+	color: #666;
+}
+
+.publisher {
+	margin-bottom: 30rpx;
+	color: #666;
+}
+
+.section {
+	margin-bottom: 30rpx;
+}
+
+.subtitle {
+	font-size: 32rpx;
+	font-weight: bold;
+	margin: 20rpx 0;
+	display: block;
+}
+
+.bold {
+	font-weight: bold;
+}
+
+.list {
+	margin-left: 30rpx;
+}
+
+.list-item {
+	margin: 15rpx 0;
+}
+
+.sub-list {
+	margin-left: 30rpx;
+	margin-top: 10rpx;
+}
+
+.sub-list-item {
+	margin: 10rpx 0;
+}
+
+.link {
+	color: #007aff;
+	text-decoration: underline;
+	margin: 10rpx 0;
+}
+
+.contact-info {
+	margin: 15rpx 0;
+}
+</style>

+ 3 - 3
static/agreement.html

@@ -15,13 +15,13 @@
 </head>
 <body>
 
-    <h1>DEEP OIL用户服务协议</h1>
+    <h1>DeepOil用户服务协议</h1>
     <p class="update">更新日期:2025年12月10日<br>生效日期:2025年12月10日</p>
 
-    <p class="important">【特别提示】请您在开始使用DEEP OIL之前,认真阅读、充分理解本《用户服务协议》(下称“本协议”)的全部内容,特别是涉及您重大权益的加粗、下划线或斜体等显著标识的条款。如您对本协议有任何疑问,请联系客服咨询。如您不同意本协议的任意内容,请立即停止使用本软件及相关服务。您的下载、安装、登录、使用等行为即视为您已阅读并同意接受本协议全部内容的约束。</p>
+    <p class="important">【特别提示】请您在开始使用DeepOil之前,认真阅读、充分理解本《用户服务协议》(下称“本协议”)的全部内容,特别是涉及您重大权益的加粗、下划线或斜体等显著标识的条款。如您对本协议有任何疑问,请联系客服咨询。如您不同意本协议的任意内容,请立即停止使用本软件及相关服务。您的下载、安装、登录、使用等行为即视为您已阅读并同意接受本协议全部内容的约束。</p>
 
     <h2>一、 协议的范围及确认</h2>
-    <p>1.1 本协议是您(下称“用户”)与山东瑞气能源技术有限公司(下称“我们”或“平台”)之间关于下载、安装、使用本软件(“DEEP OIL”),以及使用我们提供的相关服务(下称“服务”)所订立的协议。</p>
+    <p>1.1 本协议是您(下称“用户”)与山东瑞气能源技术有限公司(下称“我们”或“平台”)之间关于下载、安装、使用本软件(“DeepOil”),以及使用我们提供的相关服务(下称“服务”)所订立的协议。</p>
     <p>1.2 本协议内容同时包括我们可能不时发布的关于本服务的<strong>相关规则、公告、声明</strong>。该等内容一经正式发布,即为本协议不可分割的组成部分,您同样应当遵守。</p>
     <p>1.3 您承诺在开始使用本服务时已是具备完全民事行为能力的自然人、法人或其他组织。若您不具备前述主体资格,请在法定监护人的陪同下阅读并判断是否同意本协议,且您及您的监护人应承担因此导致的一切后果。</p>
 

+ 4 - 2
static/privacy.html

@@ -15,10 +15,12 @@
 </head>
 <body>
 
-    <h1>DEEP OIL 隐私政策</h1>
+    <h1>DeepOil 隐私政策</h1>
     <p class="update">更新日期:2025年12月10日<br>生效日期:2025年12月10日</p>
+    <p>发布主体:山东瑞气能源技术有限公司(统一社会信用代码:91370502MA3FBXDRXU;联系邮箱:
+wubj@keruigroup.com;注册地址:山东省东营市东营区南二路233号)</p>
 
-    <p>欢迎使用DEEP OIL!我们深知个人信息对您的重要性,并庄严承诺保护您的隐私安全。本政策旨在清晰说明在您使用我们的产品与服务时,我们如何收集、使用、存储、共享和保护您的个人信息,以及您享有何种权利。</p>
+    <p>欢迎使用DeepOil!我们深知个人信息对您的重要性,并庄严承诺保护您的隐私安全。本政策旨在清晰说明在您使用我们的产品与服务时,我们如何收集、使用、存储、共享和保护您的个人信息,以及您享有何种权利。</p>
     <p><strong>请您在使用前,仔细阅读并理解本政策的全部内容。当您开始使用或继续使用我们的服务,即表示您已完全同意本政策的内容。</strong>如您有任何疑问,请联系我们。</p>
     <p>
       我们的产品基于DCloud uni-app(5+ App/Wap2App)开发,应用运行期间需要收集您的设备唯一识别码(IMEI/android ID/DEVICE_ID/IDFA、SIM 卡 IMSI 信息、OAID)以提供统计分析服务,并通过应用启动数据及异常错误日志分析改进性能和用户体验,为用户提供更好的服务。