草原探险用户端 v1.0

This commit is contained in:
youpaishidifu
2026-06-20 11:25:36 +08:00
commit 931b4a9ad5
13 changed files with 832 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
node_modules/
unpackage/
.hbuilderx/
.DS_Store
git仓库.txt
+17
View 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>
+257
View File
@@ -0,0 +1,257 @@
/* ============================================
SDF1 App Shell — Gold & Obsidian Theme
============================================ */
:root {
--bg-deep: #06060b;
--bg-surface: #0e0e18;
--bg-card: #14141f;
--gold: #c9a44a;
--gold-dim: #a08339;
--gold-glow: rgba(201, 164, 74, 0.15);
--text-primary: #e8e4dc;
--text-muted: #6b6878;
--safe-top: env(safe-area-inset-top, 0px);
--safe-bottom: env(safe-area-inset-bottom, 0px);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
html, body {
width: 100%;
height: 100%;
overflow: hidden;
background: var(--bg-deep);
font-family: 'Noto Sans SC', 'Outfit', sans-serif;
color: var(--text-primary);
-webkit-font-smoothing: antialiased;
}
/* ---- Utilities ---- */
.hidden { display: none !important; }
/* ---- Splash Screen ---- */
.splash {
position: fixed;
inset: 0;
z-index: 9999;
background: var(--bg-deep);
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.5s ease, visibility 0.5s ease;
}
.splash.fade-out {
opacity: 0;
visibility: hidden;
}
.splash-inner {
text-align: center;
animation: splashReveal 0.8s ease forwards;
}
@keyframes splashReveal {
from {
opacity: 0;
transform: translateY(16px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.splash-icon {
width: 80px;
height: 80px;
margin: 0 auto 24px;
animation: iconPulse 2s ease-in-out infinite;
}
@keyframes iconPulse {
0%, 100% { transform: scale(1); filter: drop-shadow(0 0 8px var(--gold-glow)); }
50% { transform: scale(1.05); filter: drop-shadow(0 0 20px var(--gold-glow)); }
}
.splash-title {
font-family: 'Outfit', sans-serif;
font-size: 32px;
font-weight: 700;
letter-spacing: 0.15em;
color: var(--gold);
margin-bottom: 4px;
}
.splash-sub {
font-size: 14px;
font-weight: 300;
color: var(--text-muted);
letter-spacing: 0.3em;
text-transform: uppercase;
}
.splash-loader {
width: 140px;
height: 2px;
background: rgba(201, 164, 74, 0.12);
border-radius: 2px;
margin: 36px auto 0;
overflow: hidden;
}
.loader-bar {
width: 0%;
height: 100%;
background: linear-gradient(90deg, var(--gold-dim), var(--gold));
border-radius: 2px;
animation: loaderGrow 2.5s ease forwards;
}
@keyframes loaderGrow {
0% { width: 0%; }
60% { width: 70%; }
100% { width: 100%; }
}
/* ---- WebView Container ---- */
.webview-container {
position: fixed;
inset: 0;
z-index: 1;
}
.webview-container web-view,
.webview-container iframe {
width: 100%;
height: 100%;
border: none;
}
/* ---- Error Page ---- */
.error-page {
position: fixed;
inset: 0;
z-index: 100;
background: var(--bg-deep);
display: flex;
align-items: center;
justify-content: center;
}
.error-inner {
text-align: center;
padding: 40px;
animation: fadeUp 0.5s ease forwards;
}
@keyframes fadeUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.error-icon {
width: 64px;
height: 64px;
margin-bottom: 24px;
}
.error-inner h2 {
font-family: 'Outfit', sans-serif;
font-size: 22px;
font-weight: 500;
color: var(--text-primary);
margin-bottom: 8px;
}
.error-inner p {
font-size: 14px;
color: var(--text-muted);
margin-bottom: 36px;
}
.retry-btn {
display: inline-block;
padding: 14px 48px;
border: 1px solid var(--gold-dim);
background: transparent;
color: var(--gold);
font-family: 'Noto Sans SC', sans-serif;
font-size: 15px;
font-weight: 400;
letter-spacing: 0.08em;
border-radius: 6px;
cursor: pointer;
transition: all 0.25s ease;
}
.retry-btn:active {
background: var(--gold);
color: var(--bg-deep);
transform: scale(0.97);
}
/* ---- Bottom Bar ---- */
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 500;
display: flex;
justify-content: space-around;
align-items: center;
height: 56px;
padding-bottom: var(--safe-bottom);
background: linear-gradient(180deg, rgba(14,14,24,0.92) 0%, rgba(14,14,24,0.98) 100%);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border-top: 1px solid rgba(201, 164, 74, 0.1);
}
.bar-btn {
display: flex;
flex-direction: column;
align-items: center;
gap: 3px;
background: none;
border: none;
color: var(--text-muted);
font-family: 'Noto Sans SC', sans-serif;
font-size: 10px;
cursor: pointer;
padding: 6px 16px;
transition: color 0.2s ease;
-webkit-tap-highlight-color: transparent;
}
.bar-btn svg {
width: 22px;
height: 22px;
}
.bar-btn.active {
color: var(--gold);
}
.bar-btn:active {
transform: scale(0.9);
}
/* ---- 纹理叠加 ---- */
body::after {
content: '';
position: fixed;
inset: 0;
z-index: 0;
pointer-events: none;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='1'/%3E%3C/svg%3E");
background-size: 128px 128px;
opacity: 0.025;
}
+81
View File
@@ -0,0 +1,81 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<title>SDF1玩家商城</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;500;700&family=Noto+Sans+SC:wght@300;400;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<!-- 启动闪屏 -->
<div id="splash" class="splash">
<div class="splash-inner">
<div class="splash-icon">
<svg viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="80" height="80" rx="18" fill="#1a1a2e"/>
<path d="M24 28L40 20L56 28V52L40 60L24 52V28Z" stroke="#c9a44a" stroke-width="2.5" fill="none"/>
<path d="M40 20V60" stroke="#c9a44a" stroke-width="1.5" opacity="0.5"/>
<path d="M24 28L56 52" stroke="#c9a44a" stroke-width="1" opacity="0.3"/>
<path d="M56 28L24 52" stroke="#c9a44a" stroke-width="1" opacity="0.3"/>
<circle cx="40" cy="40" r="6" fill="#c9a44a" opacity="0.9"/>
<circle cx="40" cy="40" r="3" fill="#0a0a0a"/>
</svg>
</div>
<h1 class="splash-title">SDF1</h1>
<p class="splash-sub">玩家商城</p>
<div class="splash-loader">
<div class="loader-bar"></div>
</div>
</div>
</div>
<!-- 网络错误页 -->
<div id="error-page" class="error-page hidden">
<div class="error-inner">
<svg class="error-icon" viewBox="0 0 64 64" fill="none">
<circle cx="32" cy="32" r="28" stroke="#c9a44a" stroke-width="2" opacity="0.3"/>
<path d="M22 22L42 42M42 22L22 42" stroke="#c9a44a" stroke-width="2.5" stroke-linecap="round"/>
</svg>
<h2>无法连接</h2>
<p>请检查网络连接后重试</p>
<button id="retry-btn" class="retry-btn">重新连接</button>
</div>
</div>
<!-- 主 WebView 容器 -->
<div id="webview-container" class="webview-container hidden">
<web-view id="main-webview" src="https://caoyuan.ypshidifu.cn/plugin/player.php"></web-view>
</div>
<!-- 底部导航栏(备用) -->
<nav id="bottom-bar" class="bottom-bar hidden">
<button class="bar-btn active" data-action="home">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
<polyline points="9 22 9 12 15 12 15 22"/>
</svg>
<span>首页</span>
</button>
<button class="bar-btn" data-action="refresh">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="23 4 23 10 17 10"/>
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/>
</svg>
<span>刷新</span>
</button>
<button class="bar-btn" data-action="back">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="15 18 9 12 15 6"/>
</svg>
<span>返回</span>
</button>
</nav>
<script src="js/app.js"></script>
</body>
</html>
+240
View File
@@ -0,0 +1,240 @@
/**
* SDF1 App Shell
* — 启动 → 闪屏 → 加载 WebView → 错误重试
*/
(function () {
'use strict';
var MAIN_URL = 'https://caoyuan.ypshidifu.cn/plugin/player.php';
var SPLASH_MIN_DURATION = 2800; // 闪屏最少展示 2.8 秒
var splash = document.getElementById('splash');
var errorPage = document.getElementById('error-page');
var retryBtn = document.getElementById('retry-btn');
var webview = document.getElementById('main-webview');
var bottomBar = document.getElementById('bottom-bar');
var appReady = false;
var startTime = Date.now();
/* -------------------------------------------
1. 检测网络
------------------------------------------- */
function checkNetwork(callback) {
if (navigator.connection) {
var conn = navigator.connection;
if (conn.type === 'none' || conn.effectiveType === 'none') {
return callback(false);
}
}
// 简易 fetch 探测
fetch(MAIN_URL, { method: 'HEAD', mode: 'no-cors', cache: 'no-store' })
.then(function () { callback(true); })
.catch(function () { callback(false); });
}
/* -------------------------------------------
2. 初始化 WebView(HTML5+ 环境)
------------------------------------------- */
function initPlusWebView() {
if (typeof plus === 'undefined') {
// 浏览器调试模式:用 iframe 代替
var iframe = document.createElement('iframe');
iframe.src = MAIN_URL;
iframe.style.cssText = 'width:100%;height:100%;border:none;';
iframe.onload = onContentLoad;
iframe.onerror = function () { showError(); };
webview.innerHTML = '';
webview.appendChild(iframe);
return;
}
// ---- Plus 真机环境 ----
var wv = plus.webview.create(MAIN_URL, 'main', {
top: 0,
bottom: 0,
bounce: 'none',
progress: { color: '#c9a44a', height: '2px' },
useragent: { value: 'SDF1App/1.0', concat: true }
});
wv.addEventListener('loaded', onContentLoad);
wv.addEventListener('loadError', function (e) {
console.error('WebView load error:', e);
showError();
});
webview.appendChild(wv);
// 保持页面不被系统回收
plus.globalEvent.addEventListener('pause', function () {});
}
/* -------------------------------------------
3. 内容加载完成 → 隐藏闪屏
------------------------------------------- */
function onContentLoad() {
appReady = true;
var elapsed = Date.now() - startTime;
var remaining = Math.max(0, SPLASH_MIN_DURATION - elapsed);
setTimeout(function () {
splash.classList.add('fade-out');
errorPage.classList.add('hidden');
bottomBar.classList.remove('hidden');
setTimeout(function () {
splash.style.display = 'none';
}, 600);
}, remaining);
}
/* -------------------------------------------
4. 错误处理
------------------------------------------- */
function showError() {
splash.classList.add('fade-out');
setTimeout(function () {
splash.style.display = 'none';
}, 500);
errorPage.classList.remove('hidden');
bottomBar.classList.add('hidden');
}
function hideError() {
errorPage.classList.add('hidden');
}
/* -------------------------------------------
5. 底部导航事件
------------------------------------------- */
function setupBottomBar() {
var btns = bottomBar.querySelectorAll('.bar-btn');
btns.forEach(function (btn) {
btn.addEventListener('click', function () {
var action = btn.getAttribute('data-action');
// 切换 active 状态
btns.forEach(function (b) { b.classList.remove('active'); });
btn.classList.add('active');
if (action === 'refresh') {
reloadWebView();
} else if (action === 'back') {
goBack();
} else if (action === 'home') {
goHome();
}
});
});
}
function reloadWebView() {
if (typeof plus !== 'undefined') {
var wv = webview.children[0];
if (wv && wv.reload) {
wv.reload();
}
} else {
var iframe = webview.querySelector('iframe');
if (iframe) iframe.src = MAIN_URL;
}
}
function goBack() {
if (typeof plus !== 'undefined') {
var wv = webview.children[0];
if (wv && wv.canBack) {
wv.canBack(function (e) {
if (e.canBack) {
wv.back();
}
});
}
}
}
function goHome() {
if (typeof plus !== 'undefined') {
var wv = webview.children[0];
if (wv) {
wv.loadURL(MAIN_URL);
}
} else {
var iframe = webview.querySelector('iframe');
if (iframe) iframe.src = MAIN_URL;
}
}
/* -------------------------------------------
6. 物理返回键拦截(Android)
------------------------------------------- */
function setupBackButton() {
if (typeof plus === 'undefined') return;
plus.key.addEventListener('backbutton', function () {
var wv = webview.children[0];
if (wv && wv.canBack) {
wv.canBack(function (e) {
if (e.canBack) {
wv.back();
} else {
// 已在首页,按两次退出
confirmExit();
}
});
} else {
confirmExit();
}
});
}
function confirmExit() {
if (typeof plus === 'undefined') return;
plus.nativeUI.confirm(
'确定要退出应用吗?',
function (e) {
if (e.index === 0) {
plus.runtime.quit();
}
},
'退出提示',
['确定', '取消']
);
}
/* -------------------------------------------
7. 启动流程
------------------------------------------- */
function boot() {
checkNetwork(function (online) {
if (!online) {
showError();
return;
}
initPlusWebView();
});
setupBottomBar();
setupBackButton();
retryBtn.addEventListener('click', function () {
hideError();
splash.style.display = '';
splash.classList.remove('fade-out');
startTime = Date.now();
boot();
});
}
// ---- 入口 ----
if (typeof plus !== 'undefined') {
// HTML5+ ready
plus.ready(function () { boot(); });
} else if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', boot);
} else {
boot();
}
})();
+22
View 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
+70
View File
@@ -0,0 +1,70 @@
{
"name" : "草原探险用户端",
"appid" : "__UNI__307F77D",
"description" : "SDF1玩家商城客户端",
"versionName" : "1.0",
"versionCode" : 100,
"app-plus" : {
"useragent" : {
"value" : "SDF1App/1.0",
"concatenate" : true
},
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"autoclose" : false,
"waiting" : false,
"background" : "#0a0a0a"
},
"screenOrientation" : [ "portrait-primary" ],
"modules" : {},
"distribute" : {
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.INTERNET\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>"
],
"targetSdkVersion" : 30,
"minSdkVersion" : 21
},
"ios" : {
"UIBackgroundModes" : [],
"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"
}
}
}
}
},
"vueVersion" : "3",
"fallbackLocale" : "zh-Hans"
}
+17
View File
@@ -0,0 +1,17 @@
{
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "uni-app"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {}
}
+13
View File
@@ -0,0 +1,13 @@
<template>
<web-view :src="url"></web-view>
</template>
<script>
export default {
data() {
return {
url: 'https://caoyuan.ypshidifu.cn/plugin/player.php'
}
}
}
</script>
+21
View File
@@ -0,0 +1,21 @@
## 草原探险用户端app
### 1. 项目介绍
草原探险app是为草原探险服务器全体玩家打造的一款移动app,您可以在这里查看您的账号信息、兑换奖励等。
## 2. 项目构造
项目使用vue3构造
## 3.下载地址:
| 开源平台 | 下载地址 | 版本 |
| :----: | :----: | :----: |
| git.ypshidifu.cn | [https://git.ypshidifu.cn/youpaishidifu/caoyuanapp/releases/tag/1.0](https://git.ypshidifu.cn/youpaishidifu/caoyuanapp/releases/tag/1.0) | Android |
| gitcode | [https://gitcode.com/ypsdf1/caoyuanapp/releases/1.0](https://gitcode.com/ypsdf1/caoyuanapp/releases/1.0) | Android |
| github | [https://github.com/ypsdf1/caoyuanapp/releases/tag/1.0](https://github.com/ypsdf1/caoyuanapp/releases/tag/1.0) | Android |
| gitee | [https://gitee.com/nihaoshidifu/caoyuanapp/releases/tag/1.0](https://gitee.com/nihaoshidifu/caoyuanapp/releases/tag/1.0) | Android |
## 4. 使用说明
1. 下载app<br>
2. 输入你的游戏昵称和密码<br>
3. 点击登录<br>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

+13
View 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
View 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;