This commit is contained in:
atshike
2025-01-08 09:05:01 +08:00
parent fa038be10e
commit 01c62db7ac
17 changed files with 1290 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
import http from '@/utils/http'
export const EditLink = (data: any) => {
if (data && data.id) {
return http.put(`/links/${data.id}`, data)
} else {
return http.post('/links', data)
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

@@ -0,0 +1,221 @@
<script setup lang="ts">
import useForm from '@/hooks/form'
import { onMounted, ref } from 'vue'
import OssImage from '@/components/OssImage.vue'
import MaterialSelect from '@/components/MaterialSelect/MaterialSelect.vue'
import TailorUpload from '@/components/tailorUpload.vue'
import UploadImage from '@/components/uploadImage.vue'
import { ApiDomainEnableList } from '@/api/domain'
const formRef = ref()
const { formData, formLoading } = useForm({
formRef,
defVal(detail) {
return {
id: detail?.id,
type: 6, // 类型
title: detail?.title,
icon: detail?.icon,
remark: detail?.remark, // 备注
description: detail?.description, //描述
config: detail?.config
? detail?.config
: ({
version: 1, // 1是号码,2是二维码,
nickname: '',
number: '',
qr: ''
} as any)
}
}
})
const rules = {
title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
icon: [{ required: true, message: '请上传卡片封面图', trigger: 'blur' }],
'config.number': [{ required: true, message: '请输入QQ号码', trigger: 'blur' }],
'config.qr': [{ required: true, message: '请上传QQ二维码', trigger: 'blur' }],
'config.nickname': [{ required: true, message: '请输入QQ昵称', trigger: 'blur' }],
'config.domain_id': [{ required: true, message: '请选择域名', trigger: 'blur' }],
}
// 获取域名列表
const domainList = ref()
const getDomainList = async () => {
domainList.value = await ApiDomainEnableList()
}
onMounted(() => {
getDomainList()
})
</script>
<template>
<div class="main">
<el-form
:model="formData"
:rules="rules"
ref="formRef"
v-loading="formLoading"
class="form-box margin-right-40"
label-position="top"
>
<el-form-item prop="title" label="标题">
<el-input style="width: 100%" v-model="formData.title" placeholder="请输入标题"></el-input>
</el-form-item>
<el-form-item prop="description" label="描述">
<el-input style="width: 100%" v-model="formData.description" placeholder="请输入描述"></el-input>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="formData.remark" placeholder="请输入备注"></el-input>
</el-form-item>
<el-form-item label="卡片封面图" prop="icon">
<div class="item-box">
<oss-image
class="margin-right-20"
:paths="formData.icon ? [formData.icon] : []"
:width="100"
:height="100"
></oss-image>
<div>
<div class="function-img">
<div class="m-r-20">
<TailorUpload v-model="formData.icon"></TailorUpload>
</div>
<material-select v-model="formData.icon" class="margin-right-20"></material-select>
</div>
<span class="tip">只能上传jpg/png,建议大小100*100,且不超过1Mb</span>
</div>
</div>
</el-form-item>
<el-form-item prop="config.nickname" label="QQ昵称">
<el-input style="width: 100%" v-model="formData.config.nickname" placeholder="请输QQ昵称"></el-input>
</el-form-item>
<el-form-item required class="m-t-20">
<el-radio-group v-model="formData.config.version">
<el-radio :value="1" :label="1">旧版</el-radio>
<el-radio :value="2" :label="2">新版</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="QQ号码" prop="config.number" v-if="formData.config.version === 1">
<el-input v-model="formData.config.number" placeholder="请输入QQ号码"></el-input>
</el-form-item>
<el-form-item label="QQ二维码" prop="config.qr" v-if="formData.config.version === 2">
<div class="item-box">
<oss-image
class="margin-right-20"
:paths="formData.config.qr ? [formData.config.qr] : []"
:width="100"
:height="100"
></oss-image>
<div>
<div class="function-img">
<div class="m-r-20">
<upload-image
:type="['image/jpg', 'image/jpeg', 'image/png']"
:size="1"
v-model="formData.config.qr"
></upload-image>
<!-- <TailorUpload v-model="formData.config.qr"></TailorUpload>-->
</div>
<material-select v-model="formData.config.qr" class="margin-right-20"></material-select>
</div>
<span class="tip">只能上传jpg/png,建议大小100*100,且不超过1Mb</span>
</div>
</div>
</el-form-item>
<el-form-item prop="config.domain_id" label="无风险域名">
<el-select v-model="formData.config.domain_id" placeholder="请选择" style="width: 100%">
<el-option v-for="item in domainList" :key="item.id" :label="item.title" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-form>
<div class="show hidden-md-and-down">
<el-divider>
<span>预览</span>
</el-divider>
<div class="show-box">
<img class="show-box" src="@/assets/link/qqluodi.png" />
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.main {
display: flex;
.form-box {
flex: 2;
}
.show {
flex: 1;
}
}
.tip {
color: #999;
}
.show-box {
height: 400px;
margin: 0 auto;
width: 200px;
}
.show-des {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
.show-des-t {
font-size: 20px;
color: #333;
}
.show-des-b {
font-size: 14px;
color: #999;
}
}
.wx-box {
width: 100%;
height: 500px;
border: 2px solid #f1f1f1;
border-radius: 20px;
}
.wx-img {
width: 100%;
}
.wx-main {
padding: 100px 0 0 80px;
display: flex;
flex-direction: column;
width: 100%;
}
.wx-header {
margin-bottom: 20px;
display: flex;
width: 200px;
height: 60px;
}
.add-qr {
width: 100%;
color: var(--el-color-primary);
}
.qr-tip {
padding: 0 10px;
display: flex;
align-items: center;
width: 100%;
color: var(--el-color-primary);
background-color: #eff5ff;
}
.item-box {
display: flex;
align-items: center;
}
.function-img {
margin-top: 10px;
display: flex;
align-items: center;
}
</style>
@@ -0,0 +1,116 @@
<script setup lang="ts">
import useCurd from '@/hooks/curd'
import FormModal from '@/components/FormModal.vue'
import CreateOrLook from './create-or-look.vue'
import OssImage from '@/components/OssImage.vue'
import { copyLink } from '@/utils'
import useUserStore from '@/stores/modules/user'
const user = useUserStore()
const props = defineProps<{
type: any
}>()
const { state, sizeChangeHandle, currentChangeHandle, showForm, submitForm, research, deleteHandle } = useCurd({
url: '/links',
queryForm: {
type: props.type,
username: ''
}
})
</script>
<template>
<div>
<el-row :gutter="20">
<el-col :xs="24" :sm="8" :md="8" :lg="6" class="m-b-20">
<el-input style="width: 100%" v-model="state.queryForm.title" placeholder="请输入标题" clearable></el-input>
</el-col>
<el-col :xs="24" :sm="8" :md="8" :lg="6" class="m-b-20" v-if="user.userInfo.type === 3">
<el-input
style="width: 100%"
placeholder="请输入用户名"
v-model="state.queryForm.username"
clearable
></el-input>
</el-col>
<el-col :xs="24" :sm="8" :md="8" :lg="6" class="m-b-20">
<el-button type="primary" @click="research">搜索</el-button>
<el-button type="primary" :plain="true" @click="showForm">创建卡片</el-button>
</el-col>
</el-row>
<!-- 表格 -->
<el-table
:data="state.dataList"
v-loading="state.listLoading"
:header-cell-style="{
'text-align': 'center',
'background-color': '#F1F1F1',
height: '50px',
color: '#333'
}"
:cell-style="{ padding: '0', 'text-align': 'center', height: '80px', color: '#333' }"
:row-key="state.primaryKey"
>
<el-table-column prop="id" label="序号"></el-table-column>
<el-table-column label="图片">
<template #default="{ row }">
<oss-image :paths="row.icon ? [row.icon] : []" :width="60" :height="60" style="margin: 0 auto"></oss-image>
</template>
</el-table-column>
<el-table-column prop="title" label="卡片标题"></el-table-column>
<el-table-column prop="description" label="卡片描述"></el-table-column>
<el-table-column prop="" label="链接状态">
<template #default="{ row }">
<span v-if="row.status == 1">可用</span>
<span v-else style="color: red">不可用</span>
</template>
</el-table-column>
<el-table-column prop="visit_uv_count" label="浏览量UV"></el-table-column>
<el-table-column prop="expired_at" label="到期时间"></el-table-column>
<el-table-column prop="user.username" label="所属用户"></el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
<el-button type="primary" link @click="copyLink(row)">复制链接</el-button>
<el-button type="primary" link @click="showForm(row.id)">编辑</el-button>
<el-button type="primary" link @click="deleteHandle(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
:current-page="state.page"
:total="state.total"
:page-sizes="state.pageSizes"
:page-size="state.limit"
background
layout="total, sizes, prev, pager, next"
@size-change="sizeChangeHandle"
@current-change="currentChangeHandle"
/>
<!-- 弹窗 -->
<form-modal
v-if="state.formVisible === true"
v-model:visible="state.formVisible"
width="1200"
:style="{
minWidth: '700px'
}"
type="dialog"
:title="state.detailData?.id ? '编辑' : '新增'"
:loading="state.formLoading"
:detail="state.detailData"
@submit="submitForm"
cancelBtnName="取消"
okBtnName="确定"
>
<create-or-look></create-or-look>
</form-modal>
</div>
</template>
<style scoped lang="scss">
.header-right {
float: right;
}
</style>
@@ -0,0 +1,221 @@
<script setup lang="ts">
import useForm from '@/hooks/form'
import { onMounted, ref } from 'vue'
import OssImage from '@/components/OssImage.vue'
import MaterialSelect from '@/components/MaterialSelect/MaterialSelect.vue'
import TailorUpload from '@/components/tailorUpload.vue'
import UploadImage from '@/components/uploadImage.vue'
import { ApiDomainEnableList } from '@/api/domain'
const formRef = ref()
const { formData, formLoading } = useForm({
formRef,
defVal(detail) {
return {
id: detail?.id,
type: 7, // 类型
title: detail?.title,
icon: detail?.icon,
remark: detail?.remark, // 备注
description: detail?.description, //描述
config: detail?.config
? detail?.config
: ({
version: 1, // 1是号码,2是二维码,
nickname: '',
number: '',
qr: ''
} as any)
}
}
})
const rules = {
title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
icon: [{ required: true, message: '请上传卡片封面图', trigger: 'blur' }],
'config.number': [{ required: true, message: '请输入QQ群号码', trigger: 'blur' }],
'config.qr': [{ required: true, message: '请上传QQ群二维码', trigger: 'blur' }],
'config.nickname': [{ required: true, message: '请输入QQ群昵称', trigger: 'blur' }],
'config.domain_id': [{ required: true, message: '请选择域名', trigger: 'blur' }],
}
// 获取域名列表
const domainList = ref()
const getDomainList = async () => {
domainList.value = await ApiDomainEnableList()
}
onMounted(() => {
getDomainList()
})
</script>
<template>
<div class="main">
<el-form
:model="formData"
:rules="rules"
ref="formRef"
v-loading="formLoading"
class="form-box margin-right-40"
label-position="top"
>
<el-form-item prop="title" label="标题">
<el-input style="width: 100%" v-model="formData.title" placeholder="请输入标题"></el-input>
</el-form-item>
<el-form-item prop="description" label="描述">
<el-input style="width: 100%" v-model="formData.description" placeholder="请输入描述"></el-input>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="formData.remark" placeholder="请输入备注"></el-input>
</el-form-item>
<el-form-item label="卡片封面图" prop="icon">
<div class="item-box">
<oss-image
class="margin-right-20"
:paths="formData.icon ? [formData.icon] : []"
:width="100"
:height="100"
></oss-image>
<div>
<div class="function-img">
<div class="m-r-20">
<TailorUpload v-model="formData.icon"></TailorUpload>
</div>
<material-select v-model="formData.icon" class="margin-right-20"></material-select>
</div>
<span class="tip">只能上传jpg/png,建议大小100*100,且不超过1Mb</span>
</div>
</div>
</el-form-item>
<el-form-item prop="config.nickname" label="QQ群昵称">
<el-input style="width: 100%" v-model="formData.config.nickname" placeholder="请输QQ群昵称"></el-input>
</el-form-item>
<el-form-item required class="m-t-20">
<el-radio-group v-model="formData.config.version">
<el-radio :value="1" :label="1">旧版</el-radio>
<el-radio :value="2" :label="2">新版</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="QQ群号码" prop="config.number" v-if="formData.config.version === 1">
<el-input v-model="formData.config.number" placeholder="请输入QQ群号码"></el-input>
</el-form-item>
<el-form-item label="QQ群二维码" prop="config.qr" v-if="formData.config.version === 2">
<div class="item-box">
<oss-image
class="margin-right-20"
:paths="formData.config.qr ? [formData.config.qr] : []"
:width="100"
:height="100"
></oss-image>
<div>
<div class="function-img">
<div class="m-r-20">
<upload-image
:type="['image/jpg', 'image/jpeg', 'image/png']"
:size="1"
v-model="formData.config.qr"
></upload-image>
<!-- <TailorUpload v-model="formData.config.qr"></TailorUpload>-->
</div>
<material-select v-model="formData.config.qr" class="margin-right-20"></material-select>
</div>
<span class="tip">只能上传jpg/png,建议大小100*100,且不超过1Mb</span>
</div>
</div>
</el-form-item>
<el-form-item prop="config.domain_id" label="无风险域名">
<el-select v-model="formData.config.domain_id" placeholder="请选择" style="width: 100%">
<el-option v-for="item in domainList" :key="item.id" :label="item.title" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-form>
<div class="show hidden-md-and-down">
<el-divider>
<span>预览</span>
</el-divider>
<div class="show-box">
<img class="show-box" src="@/assets/link/qqluodi.png" />
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.main {
display: flex;
.form-box {
flex: 2;
}
.show {
flex: 1;
}
}
.tip {
color: #999;
}
.show-box {
height: 400px;
margin: 0 auto;
width: 200px;
}
.show-des {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
.show-des-t {
font-size: 20px;
color: #333;
}
.show-des-b {
font-size: 14px;
color: #999;
}
}
.wx-box {
width: 100%;
height: 500px;
border: 2px solid #f1f1f1;
border-radius: 20px;
}
.wx-img {
width: 100%;
}
.wx-main {
padding: 100px 0 0 80px;
display: flex;
flex-direction: column;
width: 100%;
}
.wx-header {
margin-bottom: 20px;
display: flex;
width: 200px;
height: 60px;
}
.add-qr {
width: 100%;
color: var(--el-color-primary);
}
.qr-tip {
padding: 0 10px;
display: flex;
align-items: center;
width: 100%;
color: var(--el-color-primary);
background-color: #eff5ff;
}
.item-box {
display: flex;
align-items: center;
}
.function-img {
margin-top: 10px;
display: flex;
align-items: center;
}
</style>
@@ -0,0 +1,116 @@
<script setup lang="ts">
import useCurd from '@/hooks/curd'
import FormModal from '@/components/FormModal.vue'
import CreateOrLook from './create-or-look.vue'
import OssImage from '@/components/OssImage.vue'
import { copyLink } from '@/utils'
import useUserStore from '@/stores/modules/user'
const user = useUserStore()
const props = defineProps<{
type: any
}>()
const { state, sizeChangeHandle, currentChangeHandle, showForm, submitForm, research, deleteHandle } = useCurd({
url: '/links',
queryForm: {
type: props.type,
username: ''
}
})
</script>
<template>
<div>
<el-row :gutter="20">
<el-col :xs="24" :sm="8" :md="8" :lg="6" class="m-b-20">
<el-input style="width: 100%" v-model="state.queryForm.title" placeholder="请输入标题" clearable></el-input>
</el-col>
<el-col :xs="24" :sm="8" :md="8" :lg="6" class="m-b-20" v-if="user.userInfo.type === 3">
<el-input
style="width: 100%"
placeholder="请输入用户名"
v-model="state.queryForm.username"
clearable
></el-input>
</el-col>
<el-col :xs="24" :sm="8" :md="8" :lg="6" class="m-b-20">
<el-button type="primary" @click="research">搜索</el-button>
<el-button type="primary" :plain="true" @click="showForm">创建卡片</el-button>
</el-col>
</el-row>
<!-- 表格 -->
<el-table
:data="state.dataList"
v-loading="state.listLoading"
:header-cell-style="{
'text-align': 'center',
'background-color': '#F1F1F1',
height: '50px',
color: '#333'
}"
:cell-style="{ padding: '0', 'text-align': 'center', height: '80px', color: '#333' }"
:row-key="state.primaryKey"
>
<el-table-column prop="id" label="序号"></el-table-column>
<el-table-column label="图片">
<template #default="{ row }">
<oss-image :paths="row.icon ? [row.icon] : []" :width="60" :height="60" style="margin: 0 auto"></oss-image>
</template>
</el-table-column>
<el-table-column prop="title" label="卡片标题"></el-table-column>
<el-table-column prop="description" label="卡片描述"></el-table-column>
<el-table-column prop="" label="链接状态">
<template #default="{ row }">
<span v-if="row.status == 1">可用</span>
<span v-else style="color: red">不可用</span>
</template>
</el-table-column>
<el-table-column prop="visit_uv_count" label="浏览量UV"></el-table-column>
<el-table-column prop="expired_at" label="到期时间"></el-table-column>
<el-table-column prop="user.username" label="所属用户"></el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
<el-button type="primary" link @click="copyLink(row)">复制链接</el-button>
<el-button type="primary" link @click="showForm(row.id)">编辑</el-button>
<el-button type="primary" link @click="deleteHandle(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
:current-page="state.page"
:total="state.total"
:page-sizes="state.pageSizes"
:page-size="state.limit"
background
layout="total, sizes, prev, pager, next"
@size-change="sizeChangeHandle"
@current-change="currentChangeHandle"
/>
<!-- 弹窗 -->
<form-modal
v-if="state.formVisible === true"
v-model:visible="state.formVisible"
width="1200"
:style="{
minWidth: '700px'
}"
type="dialog"
:title="state.detailData?.id ? '编辑' : '新增'"
:loading="state.formLoading"
:detail="state.detailData"
@submit="submitForm"
cancelBtnName="取消"
okBtnName="确定"
>
<create-or-look></create-or-look>
</form-modal>
</div>
</template>
<style scoped lang="scss">
.header-right {
float: right;
}
</style>
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace App\Enums;
enum MiniProgramType: int
{
case User = 1; // 用户小程序
case Platform = 2; // 平台小程序
}
@@ -0,0 +1,11 @@
<?php
namespace App\Http\Controllers;
class JumpController extends Controller
{
public function show(string $code): \Illuminate\View\View
{
return view('jump/wechat');
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Process;
use Illuminate\Support\Facades\Storage;
class QrCodeService
{
public static function qr(string $path)
{
$contents = Storage::get($path);
$tmpPath = tempnam(sys_get_temp_dir(), 'qr');
$handle = fopen($tmpPath, 'w');
fwrite($handle, $contents);
fclose($handle);
$command = sprintf('python3 %s %s', base_path('services/wechatqr-opencv/cli.py'), $tmpPath);
$scanResult = Process::timeout(20)->run($command);
unlink($tmpPath);
if ($scanResult->failed()) {
Log::error('微信二维码识别失败', ['path' => $path, 'error' => $scanResult->output()]);
return false;
}
return trim($scanResult->output());
}
}
+99
View File
@@ -0,0 +1,99 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>火星快链安装</title>
<link rel="stylesheet" type="text/css" href="https://www.layuicdn.com/layui/css/layui.css"/>
<link rel="stylesheet" type="text/css" href="/css/install.css"/>
<link rel="shortcut icon" href="favicon.ico"/>
</head>
<body>
<div class="mounted" id="mounted">
<div class="mounted-box">
<form method="post" action="?step=2">
<div class="mounted-title">安装步骤</div>
<div class="mounted-container" id="tab">
<ul class="mounted-nav" id="nav">
<li @if($step == "1") class="active" @endif>许可协议</li>
<li @if($step == "2") class="active" @endif>环境监测</li>
<li @if($step == "3") class="active" @endif>参数配置</li>
<li @if($step >= "4") class="active" @endif>安装</li>
</ul>
<!-- 阅读许可 -->
<div class="mounted-content-item show">
<div class="content-header">
开源系统授权协议
</div>
<div class="content">
<h2>版权所有(c)2019-<?=date('Y')?>,火星快链团队保留所有权利。</h2>
<p class="mt16">
<p class="mt6">为了正确并合法的使用本软件,请你在使用前务必阅读清楚下面的协议条款:</p>
<h3 class="mt16">一、本授权协议适用且仅适用于火星快链开源软件产品任何版本。</h3>
<h3 class="mt16">二、协议许可的权利</h3>
<p class="mt6">
1.免费版本可免费商用,不能私自去除官方版权。付费版本需要取得商业授权方可使用,可以去除官方版权,否则会被视为盗版行为并承担相应法律责任。
</p>
<p class="mt6">
2.请尊重火星快链团队劳动成果,严禁使用本系统转手、转卖、倒卖或二次开发后转手、转卖、倒卖等商业行为。
</p>
<p class="mt6">
3.任何企业和个人不允许对程序代码以任何形式任何目的再发布。
</p>
<p class="mt6">
4.你可以在协议规定的约束和限制范围内修改系列开源软件产品或界面风格以适应你的网站要求。
</p>
<p class="mt6">
5.你拥有使用本软件构建的系统全部内容所有权,并独立承担与这些内容的相关法律义务。
</p>
<p class="mt6">
6.获得商业授权之后,你可以将本软件应用于商业用途,同时依据所购买的授权类型中确定的技术支持内容,自购买时刻起,在技术支持期限内拥有通过指定的方式获得指定范围内的技术支持服务。商业授权用户享有反映和提出意见的权力,相关意见将被作为首要考虑,但没有一定被采纳的承诺或保证。
</p>
<h3 class="mt6">三、协议规定的约束和限制</h3>
<p class="mt6">
1.免费版本可免费商用,不能私自去除官方版权。付费版本需要取得商业授权方可使用,可以去除官方版权,否则会被视为盗版行为并承担相应法律责任。
</p>
<p class="mt6">
2.未经许可,不得对本软件或与之关联的商业授权进行出租、出售、抵押或发放子许可证。
</p>
<p class="mt6">
3.未经许可,禁止在开源系统的整体或任何部分基础上以发展任何派生版本、修改版本或第三方版本用于重新分发。
</p>
<p class="mt6">
4.如果你未能遵守本协议的条款,你的授权将被终止,所被许可的权利将被收回,并承担相应法律责任。
</p>
<h3 class="mt6">四、有限担保和免责声明</h3>
<p class="mt6">
1.本软件及所附带的文件是作为不提供任何明确的或隐含的赔偿或担保的形式提供的。
</p>
<p class="mt6">
2.用户出于自愿而使用本软件,你必须了解使用本软件的风险,在尚未购买产品技术服务之前,我们不承诺对免费用户提供任何形式的技术支持、使用担保,也不承担任何因使用本软件而产生问题的相关责任。
</p>
<p class="mt6">
3.电子文本形式的授权协议如同双方书面签署的协议一样,具有完全的和等同的法律效力。你一旦开始确认本协议并安装本软件,即被视为完全理解并接受本协议的各项条款,在享有上述条款授予的权力的同时,受到相关的约束和限制。协议许可范围以外的行为,将直接违反本授权协议并构成侵权,我们有权随时终止授权,责令停止损害,并保留追究相关责任的权力。
</p>
<p class="mt6">
4.如果本软件带有其它软件的整合API示范例子包,这些文件版权不属于本软件官方,并且这些文件是没经过授权发布的,请参考相关软件的使用许可合法的使用。
</p>
<br><br>
<p class="mt6">
-----------------------------------------------------
</p>
</div>
</div>
</div>
<div class="form-btn">
<div class="item-btn-group show">
<button class="accept-btn">我已阅读并同意</button>
<input type="hidden" name="_token" value="{{ csrf_token() }}" />
</div>
</div>
</form>
</div>
</div>
<footer>
Copyright © 2019-<?=date('Y')?>
</footer>
<script src="https://www.layuicdn.com/layui/layui.js"></script>
</body>
</html>
+221
View File
@@ -0,0 +1,221 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>火星快链安装</title>
<link rel="stylesheet" type="text/css" href="https://www.layuicdn.com/layui/css/layui.css"/>
<link rel="stylesheet" type="text/css" href="/css/install.css"/>
<link rel="shortcut icon" href="favicon.ico"/>
</head>
<body>
<div class="mounted" id="mounted">
<div class="mounted-box">
@if ($errors->any())
<div style="color: red;">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form method="post" action="?step={!! $nextStep !!}" name="main_form">
<div class="mounted-title">安装步骤</div>
<div class="mounted-container" id="tab">
<ul class="mounted-nav" id="nav">
<li @if($step == "1") class="active" @endif>许可协议</li>
<li @if($step == "2") class="active" @endif>环境监测</li>
<li @if($step == "3") class="active" @endif>参数配置</li>
<li @if($step >= "4") class="active" @endif>安装</li>
</ul>
<!-- 检查信息 -->
<div class="mounted-content-item show">
<div class="mounted-env-container">
<div class="mounted-item">
<div class="content-header">
服务器信息
</div>
<div class="content-table">
<table class="layui-table" lay-skin="line">
<colgroup>
<col width="210">
<col width="730">
</colgroup>
<thead>
<tr>
<th>参数</th>
<th>值</th>
</tr>
</thead>
<tbody>
<tr>
<td>服务器操作系统</td>
<td>{!! PHP_OS !!}</td>
</tr>
<tr>
<td>web服务器环境</td>
<td>{!! $_SERVER['SERVER_SOFTWARE'] !!}</td>
</tr>
<tr>
<td>PHP版本</td>
<td>{!! phpversion() !!}</td>
</tr>
<tr>
<td>程序安装目录</td>
<td>{!! base_path() !!}</td>
</tr>
<tr>
<td>磁盘空间</td>
<td>{!! $chk['fred_disk_space'] !!}</td>
</tr>
<tr>
<td>上传限制</td>
<td>
@if(ini_get('file_uploads'))
{!! ini_get('upload_max_filesize') !!}
@else
禁止上传
@endif
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="mounted-tips mt16">PHP环境要求必须满足下列所有条件,否则系统或系统部分功能将无法使用。</div>
<div class="mounted-item mt16">
<div class="content-header">
PHP环境要求
</div>
<div class="content-table">
<table class="layui-table" lay-skin="line">
<colgroup>
<col width="210">
<col width="210">
<col width="400">
</colgroup>
<thead>
<tr>
<th>选项</th>
<th>要求</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr>
<td>PHP版本</td>
<td>≥8.1</td>
<td>{!! $chk['php_version'] !!}</td>
</tr>
<tr>
<td>PDO_MYSQL</td>
<td>支持</td>
<td>{!! $chk['pdo_mysql'] !!}</td>
</tr>
<tr>
<td>allow_url_fopen</td>
<td>支持 (建议支持cURL)</td>
<td>{!! $chk['curl'] !!}</td>
</tr>
<tr>
<td>GD2</td>
<td>支持</td>
<td>{!! $chk['gd2'] !!}</td>
</tr>
<tr>
<td>fileinfo</td>
<td>支持</td>
<td>{!! $chk['fileinfo'] !!}</td>
</tr>
<tr>
<td>putenv</td>
<td>支持</td>
<td>{!! $chk['putenv'] !!}</td>
</tr>
<tr>
<td>symlink</td>
<td>支持</td>
<td>{!! $chk['symlink'] !!}</td>
</tr>
<tr>
<td>proc_open</td>
<td>支持</td>
<td>{!! $chk['proc_open'] !!}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="mounted-tips mt16">
系统要求安装目录下的storage必须可写,才能使用系统的所有功能。
</div>
<div class="mounted-item mt16">
<div class="content-header">
目录权限监测
</div>
<div class="content-table">
<table class="layui-table" lay-skin="line">
<colgroup>
<col width="210">
<col width="210">
<col width="400">
</colgroup>
<thead>
<tr>
<th>目录</th>
<th>要求</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr>
<td>/server/storage/logs</td>
<td>logs目录可写</td>
<td>{!! $chk['log'] !!}</td>
</tr>
<tr>
<td>/server/storage/app/public</td>
<td>uploads目录可写</td>
<td>{!! $chk['upload'] !!}</td>
</tr>
<tr>
<td>/server/storage/framework</td>
<td>cache目录可写</td>
<td>{!! $chk['cache'] !!}</td>
</tr>
<tr>
<td>/server/.env</td>
<td>.env文件可写</td>
<td>{!! $chk['env'] !!}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="form-btn">
<div class="item-btn-group show">
<a href="?step={!! $lastStep !!}" class="cancel-btn" style="padding: 7px 63px;margin-right: 16px">返回</a>
<button class="accept-btn @if(!$is_goon) action @endif" style="padding: 7px 63px;">
继续
</button>
<input type="hidden" name="_token" value="{{ csrf_token() }}" />
&nbsp;
<a href="?step={!! $step !!}" class="accept-btn" style="padding: 7px 63px;">重新检查
</a>
</div>
</div>
</form>
</div>
</div>
<footer>
Copyright © 2019-<?=date('Y')?>
</footer>
<script src="https://www.layuicdn.com/layui/layui.js"></script>
</body>
</html>
+140
View File
@@ -0,0 +1,140 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>火星快链安装</title>
<link rel="stylesheet" type="text/css" href="https://www.layuicdn.com/layui/css/layui.css"/>
<link rel="stylesheet" type="text/css" href="/css/install.css"/>
<link rel="shortcut icon" href="favicon.ico"/>
</head>
<body>
<div class="mounted" id="mounted">
<div class="mounted-box">
@if ($errors->any())
<div style="color: red;">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form method="post" action="?step={!! $nextStep !!}" name="main_form">
<div class="mounted-title">安装步骤</div>
<div class="mounted-container" id="tab">
<ul class="mounted-nav" id="nav">
<li @if($step == "1") class="active" @endif>许可协议</li>
<li @if($step == "2") class="active" @endif>环境监测</li>
<li @if($step == "3") class="active" @endif>参数配置</li>
<li @if($step >= "4") class="active" @endif>安装</li>
</ul>
<!-- 数据库设置 -->
<div class="mounted-content-item show">
<div class="mounted-item">
<div class="content-header">
数据库选项
</div>
<div class="content-form">
<div class="form-box-item">
<div class="form-desc">
数据库主机
</div>
<div>
<input type="text" name="host" value="{!! $post['host'] !!}"/>
</div>
</div>
<div class="form-box-item">
<div class="form-desc">
端口号
</div>
<div>
<input type="text" name="port" value="{!! $post['port'] !!}"/>
</div>
</div>
<div class="form-box-item">
<div class="form-desc">
数据库用户
</div>
<div>
<input type="text" name="user" value="{!! $post['user'] !!}"/>
</div>
</div>
<div class="form-box-item">
<div class="form-desc">
数据库密码
</div>
<div>
<input type="text" name="password" value="{!! $post['password'] !!}"/>
</div>
</div>
<div class="form-box-item">
<div class="form-desc">
数据库名称
</div>
<div>
<input type="text" name="name" value="{!! $post['name'] !!}"/>
</div>
</div>
</div>
</div>
<div class="mounted-item">
<div class="content-header mt16">
管理选项
</div>
<div class="content-form">
<div class="form-box-item">
<div class="form-desc">
管理员账号
</div>
<div>
<input type="text" name="admin_user" value="{!! $post['admin_user'] !!}"/>
</div>
</div>
<div class="form-box-item">
<div class="form-desc">
管理员密码
</div>
<div>
<input type="password" name="admin_password" value="{!! $post['admin_password'] !!}"/>
</div>
</div>
<div class="form-box-item">
<div class="form-desc">
确认密码
</div>
<div>
<input type="password" name="admin_password_confirmation" value="{!! $post['admin_confirm_password'] !!}"/>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="form-btn">
<div class="item-btn-group show">
<a href="?step={!! $lastStep !!}" class="cancel-btn" style="padding: 7px 63px;margin-right: 16px">返回</a>
<button class="accept-btn @if(!$is_goon) action @endif" style="padding: 7px 63px;">
继续
</button>
<input type="hidden" name="_token" value="{{ csrf_token() }}" />
&nbsp;
<a href="?step={!! $step !!}" class="accept-btn" style="padding: 7px 63px;">重新检查
</a>
</div>
</div>
</form>
</div>
</div>
<footer>
Copyright © 2019-<?=date('Y')?>
</footer>
<script src="https://www.layuicdn.com/layui/layui.js"></script>
</body>
</html>
+56
View File
@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>火星快链安装</title>
<link rel="stylesheet" type="text/css" href="https://www.layuicdn.com/layui/css/layui.css"/>
<link rel="stylesheet" type="text/css" href="/css/install.css"/>
<link rel="shortcut icon" href="favicon.ico"/>
</head>
<body>
<div class="mounted" id="mounted">
<div class="mounted-box">
<form method="post" action="">
<div class="mounted-title">安装步骤</div>
<div class="mounted-container" id="tab">
<ul class="mounted-nav" id="nav">
<li @if($step == "1") class="active" @endif>许可协议</li>
<li @if($step == "2") class="active" @endif>环境监测</li>
<li @if($step == "3") class="active" @endif>参数配置</li>
<li @if($step >= "4") class="active" @endif>安装</li>
</ul>
<!-- 安装中 -->
<div class="mounted-content-item show">
<div id="mounting">
<div class="content-header">
正在安装中
</div>
</div>
<div class="show" id="mounting-success">
<div class="content-header">
安装成功
</div>
<div class="success-content">
<div class="mt16 result">安装完成,进入管理后台</div>
<div class="tips">
为了您站点的安全,安装完成后即可将网站根目录下的“install”文件夹删除。
</div>
<div class="btn-group">
<a class="btn" href="/" style="margin-left: 20px;">进入首页</a>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
<footer>
Copyright © 2019-<?=date('Y')?>
</footer>
<script src="https://www.layuicdn.com/layui/layui.js"></script>
</body>
</html>
+5
View File
@@ -0,0 +1,5 @@
## install
```bash
pip3 install opencv-contrib-python
```
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env python3
import cv2
import sys
from cv2.wechat_qrcode import WeChatQRCode
def qr(new_width, new_height, mode):
resized = cv2.resize(image, (new_width, new_height), interpolation=cv2.INTER_CUBIC)
gray = cv2.cvtColor(resized, mode) # cv2.COLOR_RGB2GRAY
detect_obj = WeChatQRCode()
results, _ = detect_obj.detectAndDecode(gray)
if len(results) < 1:
return ""
return results[0]
try:
image = cv2.imread(sys.argv[1])
# 放大multiple倍,转灰度
img_size = image.shape
new_width = 2000
new_height = int(img_size[0] * (new_width / img_size[1]))
results = qr(new_width, new_height, cv2.COLOR_RGB2GRAY)
if results == "":
results = qr(new_width, new_height, cv2.COLOR_RGB2HSV)
print(results)
sys.exit(0)
print(results)
sys.exit(0)
except Exception as e: # 捕获具体异常
print(f"Error occurred: {str(e)}")
sys.exit(1)