小程序支持主题管理

This commit is contained in:
devil 2020-11-21 16:42:35 +08:00
parent 3afb6cd3e7
commit 2a5c0cfba1
1748 changed files with 1343 additions and 172 deletions

View File

@ -12,6 +12,7 @@ namespace app\admin\controller;
use app\service\AppMiniService;
use app\service\ConfigService;
use app\service\StoreService;
/**
* 小程序管理
@ -23,10 +24,11 @@ use app\service\ConfigService;
*/
class Appmini extends Common
{
private $params;
private $application_name;
private $old_path;
private $new_path;
private $params;
private $view_type;
/**
* 构造方法
@ -50,10 +52,12 @@ class Appmini extends Common
// 参数
$this->params = $this->data_request;
$this->params['application_name'] = empty($this->data_request['nav_type']) ? 'weixin' : trim($this->data_request['nav_type']);
$this->assign('nav_type', $this->params['application_name']);
// 小导航
$this->view_type = input('view_type', 'index');
}
/**
/**
* 列表
* @author Devil
* @blog http://gong.gg/
@ -63,7 +67,33 @@ class Appmini extends Common
*/
public function Index()
{
$host = 'https://shopxo.net/';
// 公共视图
$this->CurrentViewInit();
// 是否默认首页
if($this->view_type == 'index')
{
// 获取主题列表
$data = AppMiniService::ThemeList($this->params);
$this->assign('data_list', $data);
// 默认主题
$this->assign('theme', AppMiniService::$default_theme);
}
return $this->fetch($this->view_type);
}
/**
* 小程序包列表页面
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-07-13
* @desc description
*/
public function Package()
{
$host = config('shopxo.website_url');
$nav_dev_tips = [
// 微信
'weixin' => [
@ -93,13 +123,114 @@ class Appmini extends Common
];
$this->assign('nav_dev_tips', $nav_dev_tips);
// 公共视图
$this->CurrentViewInit();
// 源码包列表
$ret = AppMiniService::DownloadDataList($this->params);
$this->assign('data_list', $ret['data']);
return $this->fetch();
}
/**
* 公共视图
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-21
* @desc description
*/
public function CurrentViewInit()
{
// 操作导航类型
$this->assign('nav_type', $this->params['application_name']);
// 操作页面类型
$this->assign('view_type', $this->view_type);
// 应用商店
$this->assign('store_theme_url', StoreService::StoreThemeUrl());
// 小程序平台
$this->assign('common_appmini_type', lang('common_appmini_type'));
// 源码包列表
$ret = AppMiniService::DataList($this->params);
$this->assign('data_list', $ret['data']);
return $this->fetch();
// 是否
$this->assign('common_is_text_list', lang('common_is_text_list'));
}
/**
* 主题上传安装
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-21
* @desc description
*/
public function ThemeUpload()
{
// 是否ajax
if(!IS_AJAX)
{
return $this->error('非法访问');
}
// 开始处理
return AppMiniService::ThemeUpload($this->params);
}
/**
* 主题切换保存
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @datetime 2018-12-19T00:58:47+0800
*/
public function ThemeSave()
{
$key = AppMiniService::DefaultThemeKey($this->params);
$params[$key] = empty($this->data_request['theme']) ? 'default' : $this->data_request['theme'];
return ConfigService::ConfigSave($params);
}
/**
* 主题打包下载
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @datetime 2018-12-19T00:58:47+0800
*/
public function ThemeDownload()
{
$params = array_merge($this->params, $this->data_request);
$ret = AppMiniService::ThemeDownload($params);
if(isset($ret['code']) && $ret['code'] != 0)
{
$this->assign('msg', $ret['msg']);
return $this->fetch('public/tips_error');
} else {
return $ret;
}
}
/**
* 主题删除
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-21
* @desc description
*/
public function ThemeDelete()
{
// 是否ajax
if(!IS_AJAX)
{
return $this->error('非法访问');
}
// 开始处理
$params = array_merge($this->params, $this->data_request);
return AppMiniService::ThemeDelete($params);
}
/**
@ -112,11 +243,8 @@ class Appmini extends Common
*/
public function Config()
{
// 是否
$this->assign('common_is_text_list', lang('common_is_text_list'));
// 小程序平台
$this->assign('common_appmini_type', lang('common_appmini_type'));
// 公共视图
$this->CurrentViewInit();
// 配置信息
$this->assign('data', ConfigService::ConfigList());
@ -139,22 +267,12 @@ class Appmini extends Common
$this->error('非法访问');
}
// 配置内容
$title = MyC('common_app_mini_'.$this->params['application_name'].'_title');
$describe = MyC('common_app_mini_'.$this->params['application_name'].'_describe');
if(empty($title) || empty($describe))
{
return DataReturn('配置信息不能为空', -1);
}
// 开始操作
$this->params['app_mini_title'] = $title;
$this->params['app_mini_describe'] = $describe;
return AppMiniService::Created($this->params);
}
/**
* 保存
* 配置保存
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0

View File

@ -23,6 +23,8 @@ use app\service\StoreService;
*/
class Theme extends Common
{
private $view_type;
/**
* 构造方法
* @author Devil
@ -60,14 +62,15 @@ class Theme extends Common
// 应用商店
$this->assign('store_theme_url', StoreService::StoreThemeUrl());
// 是否默认首页
if($this->view_type == 'index')
{
// 模板列表
$this->assign('data_list', ThemeService::ThemeList());
// 获取主题列表
$data = ThemeService::ThemeList();
$this->assign('data_list', $data);
// 默认主题
$theme = MyC('common_default_theme', 'default', true);
$this->assign('theme', empty($theme) ? 'default' : $theme);
$this->assign('theme', ThemeService::DefaultTheme());
}
return $this->fetch($this->view_type);
}
@ -81,7 +84,8 @@ class Theme extends Common
*/
public function Save()
{
return ConfigService::ConfigSave($this->data_request);
$params['common_default_theme'] = empty($this->data_request['theme']) ? 'default' : $this->data_request['theme'];
return ConfigService::ConfigSave($params);
}
/**
@ -123,7 +127,7 @@ class Theme extends Common
}
/**
* 主题打包
* 主题打包下载
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0

View File

@ -0,0 +1,14 @@
<ul class="am-nav am-nav-pills table-nav">
<li {{if $view_type eq 'index'}}class="am-active"{{/if}}>
<a href="{{:MyUrl('admin/appmini/index', ['view_type'=>'index', 'nav_type'=>$nav_type])}}">当前主题</a>
</li>
<li {{if $view_type eq 'upload'}}class="am-active"{{/if}}>
<a href="{{:MyUrl('admin/appmini/index', ['view_type'=>'upload', 'nav_type'=>$nav_type])}}">主题安装</a>
</li>
<li {{if $view_type eq 'package'}}class="am-active"{{/if}}>
<a href="{{:MyUrl('admin/appmini/package', ['view_type'=>'package', 'nav_type'=>$nav_type])}}">源码包下载</a>
</li>
<li class="fr">
<a class="am-margin-left-sm" href="{{$store_theme_url}}" target="_blank">更多主题下载 <i class="am-icon-external-link"></i></a>
</li>
</ul>

View File

@ -2,11 +2,10 @@
<!-- right content start -->
<div class="content-right">
<!-- second nav start -->
{{include file="appmini/nav" /}}
<!-- second nav end -->
<div class="content">
<!-- table nav start -->
{{include file="appmini/nav" /}}
<!-- table nav end -->
<!-- form start -->
<form class="am-form form-validation view-save" action="{{:MyUrl('admin/appmini/save', ['nav_type'=>$nav_type])}}" method="POST" request-type="ajax-url" request-value="{{:MyUrl('admin/appmini/config', ['nav_type'=>$nav_type])}}">
{{switch $nav_type}}

80
application/admin/view/default/appmini/index.html Executable file → Normal file
View File

@ -1,35 +1,57 @@
<!-- 继承公共的 form -->
{{extend name="public/module/form" /}}
{{include file="public/header" /}}
<!-- 导航 -->
{{block name="form_navigation"}}
<!-- right content start -->
<div class="content-right">
<!-- second nav start -->
{{include file="appmini/nav" /}}
<!-- tips -->
<div class="am-alert am-alert-warning am-radius">
{{if config('shopxo.is_develop') eq true}}
<p>当前为开发模式</p>
<p class="am-margin-left-lg">1. 发布小程序必须采用 https 协议,上线需确认 app.js 中 request_url 参数值是否正确。</p>
<p class="am-margin-left-lg">2. 发布小程序,建议关闭开发者模式、从正式环境重新生成小程序下载使用开发者工具上传审核。</p>
{{if isset($nav_dev_tips[$nav_type])}}
<p class="am-margin-left-lg">3. 非 https 环境下,在开发者工具 -> {{$nav_dev_tips[$nav_type]['msg']}}</p>
{{/if}}
<!-- second nav end -->
<div class="content">
<!-- nav start -->
{{include file="appmini/base_nav" /}}
<!-- nav end -->
<!-- list start -->
{{if !empty($data_list)}}
<ul data-am-widget="gallery" class="am-gallery am-avg-sm-2 am-avg-md-3 am-avg-lg-4 am-gallery-bordered data-list" data-am-gallery="{}" data-select-url="{{:MyUrl('admin/appmini/themesave')}}" data-nav-type="{{$nav_type}}">
{{foreach $data_list as $v}}
<li id="data-list-{{$v.theme}}">
<div class="am-gallery-item am-radius am-padding-0 {{if $v['theme'] eq $theme}}theme-active{{/if}}">
<a href="javascript:;" class="select-theme am-block" data-theme="{{$v.theme}}">
<img src="{{$v.preview}}" alt="{{$v.name}}" class="am-block" />
</a>
<div class="am-gallery-item-bottom am-padding-sm">
<h3 class="am-gallery-title am-margin-top-0">
{{$v.name}}
<div class="am-fr am-text-right">
{{if isset($shopxo_is_develop) and $shopxo_is_develop eq true}}
<a href="{{:MyUrl('admin/appmini/themedownload', ['id'=>$v['theme'], 'nav_type'=>$nav_type])}}" class="am-icon-trash-o am-icon-download" title="打包"></a>
{{/if}}
{{if $v.is_delete eq 1}}
<a href="javascript:;" class="am-icon-trash-o submit-delete am-margin-left-sm" title="删除" data-url="{{:MyUrl('admin/appmini/themedelete', ['nav_type'=>$nav_type])}}" data-id="{{$v.theme}}"></a>
{{/if}}
</div>
</h3>
<div class="am-gallery-desc">作者:
{{if empty($v['home'])}}
{{$v.author}}
{{else /}}
<a href="{{$v.home}}" target="_blank">{{$v.author}}</a>
{{/if}}
</div>
<div class="am-gallery-desc">适用版本:{{$v.ver}}</div>
</div>
</div>
</li>
{{/foreach}}
<ul>
{{else /}}
<p>1. 生成小程序必须在 https 协议下进行操作、请配置好服务器 ssl 并使用 https 协议登录后台管理生成小程序。</p>
<p>2. 如需非 https 协议下生成小程序,请在 config/shopxo.php 文件中 is_develop值改为true开启开发者模式。</p>
{{/if}}
<!-- 教程地址-->
{{if isset($nav_dev_tips[$nav_type])}}
<p class="am-margin-top-xs">
<a href="{{$nav_dev_tips[$nav_type]['url']}}" target="_blank">查看部署教程 <i class="am-icon-external-link"></i></a>
</p>
{{include file="public/not_data" /}}
{{/if}}
<!-- lis end -->
</div>
{{/block}}
</div>
<!-- right content end -->
<!-- 表单顶部操作栏 -->
{{block name="form_operate_top"}}
<button type="button" class="am-btn am-btn-secondary am-btn-xs am-icon-refresh am-radius submit-ajax" data-url="{{:MyUrl('admin/appmini/created', ['nav_type'=>$nav_type])}}" data-view="reload" data-msg="生成时间比较长,请不要关闭浏览器窗口!"> 生成</button>
<!-- 父级内容 -->
{__block__}
{{/block}}
<!-- footer start -->
{{include file="public/footer" /}}
<!-- footer end -->

View File

@ -1,8 +1,8 @@
{{if !empty($common_appmini_type) and is_array($common_appmini_type)}}
<ul class="am-nav am-nav-pills table-nav am-margin-bottom-sm">
<ul class="am-nav am-nav-pills table-nav second-nav">
{{foreach $common_appmini_type as $nav}}
<li {{if isset($nav_type) and $nav_type eq $nav['value']}}class="am-active"{{/if}} data-type="{{$nav.value}}">
<a href="{{:MyUrl('admin/appmini/'.$action_name, ['nav_type'=>$nav['value']])}}">{{$nav.name}}</a>
<a href="{{:MyUrl('admin/appmini/'.$action_name, ['nav_type'=>$nav['value'], 'view_type'=>$view_type])}}">{{$nav.name}}</a>
</li>
{{/foreach}}
</ul>

View File

@ -0,0 +1,41 @@
<!-- 继承公共的 form -->
{{extend name="public/module/form" /}}
<!-- 内容顶部 -->
{{block name="form_content_top"}}
{{include file="appmini/nav" /}}
{{/block}}
<!-- 导航 -->
{{block name="form_navigation"}}
{{include file="appmini/base_nav" /}}
<!-- tips -->
<div class="am-alert am-alert-warning am-radius">
<p class="am-text-danger am-margin-bottom-xs am-text-lg">生成源码包采用当前设置的默认主题进行生成zip压缩包</p>
{{if config('shopxo.is_develop') eq true}}
<p>当前为开发模式</p>
<p class="am-margin-left-lg">1. 发布小程序必须采用 https 协议,上线需确认 app.js 中 request_url 参数值是否正确。</p>
<p class="am-margin-left-lg">2. 发布小程序,建议关闭开发者模式、从正式环境重新生成小程序下载使用开发者工具上传审核。</p>
{{if isset($nav_dev_tips[$nav_type])}}
<p class="am-margin-left-lg">3. 非 https 环境下,在开发者工具 -> {{$nav_dev_tips[$nav_type]['msg']}}</p>
{{/if}}
{{else /}}
<p>1. 生成小程序必须在 https 协议下进行操作、请配置好服务器 ssl 并使用 https 协议登录后台管理生成小程序。</p>
<p>2. 如需非 https 协议下生成小程序,请在 config/shopxo.php 文件中 is_develop值改为true开启开发者模式。</p>
{{/if}}
<!-- 教程地址-->
{{if isset($nav_dev_tips[$nav_type])}}
<p class="am-margin-top-xs">
<a href="{{$nav_dev_tips[$nav_type]['url']}}" target="_blank">查看部署教程 <i class="am-icon-external-link"></i></a>
</p>
{{/if}}
</div>
{{/block}}
<!-- 表单顶部操作栏 -->
{{block name="form_operate_top"}}
<button type="button" class="am-btn am-btn-secondary am-btn-xs am-icon-refresh am-radius submit-ajax" data-url="{{:MyUrl('admin/appmini/created', ['nav_type'=>$nav_type])}}" data-view="reload" data-msg="生成时间比较长,请不要关闭浏览器窗口!"> 生成</button>
<!-- 父级内容 -->
{__block__}
{{/block}}

View File

@ -0,0 +1,34 @@
{{include file="public/header" /}}
<!-- right content start -->
<div class="content-right">
<!-- second nav start -->
{{include file="appmini/nav" /}}
<!-- second nav end -->
<div class="content">
<!-- nav start -->
{{include file="appmini/base_nav" /}}
<!-- nav end -->
<!-- form start -->
<form class="am-form form-validation view-save am-margin-top-sm" action="{{:MyUrl('admin/appmini/themeupload')}}" method="POST" request-type="ajax-url" request-value="{{:MyUrl('admin/appmini/index', ['nav_type'=>$nav_type])}}" enctype="multipart/form-data">
<div class="am-form-group am-form-group-refreshing am-margin-bottom-0 am-form-file">
<button type="button" class="am-btn am-btn-default am-btn-sm am-radius">
<i class="am-icon-cloud-upload"></i> 选择文件</button>
<input type="file" name="theme" class="file-event" data-tips-tag="#form-theme-tips" data-validation-message="请选择需要上传的文件" accept=".zip" required />
<span class="tips am-text-xs">上传一个zip压缩格式的主题安装包</span>
<div id="form-theme-tips" class="am-margin-top-xs"></div>
</div>
<div class="am-form-group am-form-group-refreshing">
<input type="hidden" name="nav_type" value="{{$nav_type}}" />
<button type="submit" class="am-btn am-btn-primary am-radius btn-loading-example am-btn-sm" data-am-loading="{loadingText:'上传中...'}">确认上传</button>
</div>
</form>
<!-- form end -->
</div>
</div>
<!-- right content end -->
<!-- footer start -->
{{include file="public/footer" /}}
<!-- footer end -->

View File

@ -22,6 +22,11 @@
<!-- right content start -->
<div class="content-right">
<!-- content top start -->
<div class="content-top">
{{block name="form_content_top"}}{{/block}}
</div>
<!-- content top end -->
<div class="content form-table-content">
<!-- content inside top hook -->
{{if isset($shopxo_is_develop) and $shopxo_is_develop eq true and (!isset($is_footer) or $is_footer eq 1)}}

View File

@ -14,14 +14,14 @@
<li id="data-list-{{$v.theme}}">
<div class="am-gallery-item am-radius am-padding-0 {{if $v['theme'] eq $theme}}theme-active{{/if}}">
<a href="javascript:;" class="select-theme am-block" data-theme="{{$v.theme}}">
<img src="{{$v.preview}}" alt="{{$v.name}}" />
<img src="{{$v.preview}}" alt="{{$v.name}}" class="am-block" />
</a>
<div class="am-gallery-item-bottom">
<div class="am-gallery-item-bottom am-padding-sm">
<h3 class="am-gallery-title am-margin-top-0">
{{$v.name}}
<div class="am-fr am-text-right">
{{if isset($shopxo_is_develop) and $shopxo_is_develop eq true}}
<a href="{{:MyUrl('admin/theme/download', array('id'=>$v['theme']))}}" class="am-icon-trash-o am-icon-download" title="打包" data-url="{{:MyUrl('admin/theme/download')}}" data-id="{{$v.theme}}"></a>
<a href="{{:MyUrl('admin/theme/download', ['id'=>$v['theme']])}}" class="am-icon-trash-o am-icon-download" title="打包"></a>
{{/if}}
{{if $v.is_delete eq 1}}
<a href="javascript:;" class="am-icon-trash-o submit-delete am-margin-left-sm" title="删除" data-url="{{:MyUrl('admin/theme/delete')}}" data-id="{{$v.theme}}"></a>

View File

@ -20,13 +20,16 @@ namespace app\service;
class AppMiniService
{
// 当前小程序包名称
private static $application_name;
public static $application_name;
// 原包地址/操作地址
private static $old_root;
private static $new_root;
private static $old_path;
private static $new_path;
public static $old_root;
public static $new_root;
public static $old_path;
public static $new_path;
// 当前默认主题
public static $default_theme;
/**
* @author Devil
@ -39,24 +42,339 @@ class AppMiniService
public static function Init($params = [])
{
// 当前小程序包名称
self::$application_name = isset($params['application_name']) ? $params['application_name'] : 'alipay';
self::$application_name = isset($params['application_name']) ? $params['application_name'] : 'weixin';
// 原包地址/操作地址
self::$old_root = ROOT.'sourcecode';
self::$new_root = ROOT.'public'.DS.'download'.DS.'sourcecode';
self::$old_path = self::$old_root.DS.self::$application_name;
self::$new_path = self::$new_root.DS.self::$application_name;
// 默认主题
self::$default_theme = self::DefaultTheme();
}
/**
* 获取小程序生成列表
* 默认主题标识符
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-20
* @desc description
* @param [array] $params [输入参数]
*/
public static function DefaultTheme($params = [])
{
return MyC(self::DefaultThemeKey($params), 'default', true);
}
/**
* 默认主题标识符数据key
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-21
* @desc description
* @param [array] $params [输入参数]
*/
public static function DefaultThemeKey($params = [])
{
if(empty(self::$application_name))
{
// 初始化
self::Init($params);
}
return 'common_app_mini_'.self::$application_name.'_default_theme';
}
/**
* 获取模板列表
* @author Devil
* @blog http://gong.gg/
* @version 0.0.1
* @datetime 2017-05-10T10:24:40+0800
* @param [array] $params [输入参数]
* @return [array] [模板列表]
*/
public static function ThemeList($params = [])
{
// 初始化
self::Init($params);
// 读取目录
$result = [];
$dir = self::$old_path.DS;
if(is_dir($dir))
{
if($dh = opendir($dir))
{
$img_obj = \base\Images::Instance();
$default_preview = __MY_PUBLIC_URL__.'static'.DS.'common'.DS.'images'.DS.'default-preview.jpg';
while(($temp_file = readdir($dh)) !== false)
{
if(substr($temp_file, 0, 1) == '.')
{
continue;
}
$config = $dir.$temp_file.DS.'config.json';
if(!file_exists($config))
{
continue;
}
// 读取配置文件
$data = json_decode(file_get_contents($config), true);
if(!empty($data) && is_array($data))
{
if(empty($data['name']) || empty($data['ver']) || empty($data['author']))
{
continue;
}
$preview = $dir.$temp_file.DS.'images'.DS.'preview.jpg';
$result[] = array(
'theme' => $temp_file,
'name' => htmlentities($data['name']),
'ver' => str_replace(array('',','), ', ', htmlentities($data['ver'])),
'author' => htmlentities($data['author']),
'home' => isset($data['home']) ? $data['home'] : '',
'preview' => $img_obj->ImageToBase64(file_exists($preview) ? $preview : $default_preview),
'is_delete' => ($temp_file == 'default') ? 0 : 1,
);
}
}
closedir($dh);
}
}
return $result;
}
/**
* 模板上传
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @datetime 2018-12-19T00:53:45+0800
* @param [array] $params [输入参数]
*/
public static function ThemeUpload($params = [])
{
// 初始化
self::Init($params);
// 文件上传校验
$error = FileUploadError('theme');
if($error !== true)
{
return DataReturn($error, -1);
}
// 文件格式化校验
$type = array('application/zip', 'application/octet-stream', 'application/x-zip-compressed');
if(!in_array($_FILES['theme']['type'], $type))
{
return DataReturn('文件格式有误请上传zip压缩包', -2);
}
// 主题目录
$dir = self::$old_path.DS;
// 目录是否有权限
if(!is_writable($dir))
{
return DataReturn('视图目录没权限['.$dir.']', -10);
}
// 开始解压文件
$resource = zip_open($_FILES['theme']['tmp_name']);
while(($temp_resource = zip_read($resource)) !== false)
{
if(zip_entry_open($resource, $temp_resource))
{
// 资源文件
$file = zip_entry_name($temp_resource);
// 排除系统.开头的临时文件和目录
if(strpos($file, '/.') !== false)
{
continue;
}
// 截取文件路径
$file_path = $dir.substr($file, 0, strrpos($file, '/'));
// 路径不存在则创建
if(!is_dir($file_path))
{
mkdir($file_path, 0777, true);
}
// 如果不是目录则写入文件
if(!is_dir($dir.$file))
{
// 读取这个文件
$file_size = zip_entry_filesize($temp_resource);
$file_content = zip_entry_read($temp_resource, $file_size);
file_put_contents($dir.$file, $file_content);
}
// 关闭目录项
zip_entry_close($temp_resource);
}
}
return DataReturn('安装成功');
}
/**
* 模板删除
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @datetime 2018-12-19T00:46:02+0800
* @param [array] $params [输入参数]
*/
public static function ThemeDelete($params = [])
{
// 请求参数
$p = [
[
'checked_type' => 'empty',
'key_name' => 'id',
'error_msg' => '模板id有误',
],
];
$ret = ParamsChecked($params, $p);
if($ret !== true)
{
return DataReturn($ret, -1);
}
// 初始化
self::Init($params);
// 防止路径回溯
$id = htmlentities(str_replace(array('.', '/', '\\', ':'), '', strip_tags($params['id'])));
if(empty($id))
{
return DataReturn('主题名称有误', -1);
}
// default不能删除
if($id == 'default')
{
return DataReturn('系统模板不能删除', -2);
}
// 不能删除正在使用的主题
if(self::$default_theme == $id)
{
return DataReturn('不能删除正在使用的主题', -2);
}
// 开始删除主题
if(\base\FileUtil::UnlinkDir(self::$old_path.DS.$id))
{
return DataReturn('删除成功');
}
return DataReturn('删除失败或资源不存在', -100);
}
/**
* 主题打包
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2019-03-22
* @desc description
* @param [array] $params [输入参数]
*/
public static function ThemeDownload($params = [])
{
// 请求参数
$p = [
[
'checked_type' => 'empty',
'key_name' => 'id',
'error_msg' => '模板id有误',
],
];
$ret = ParamsChecked($params, $p);
if($ret !== true)
{
return DataReturn($ret, -1);
}
// 初始化
self::Init($params);
// 是否开启开发者模式
if(config('shopxo.is_develop') !== true)
{
return DataReturn('请先开启开发者模式', -1);
}
// 防止路径回溯
$theme = htmlentities(str_replace(array('.', '/', '\\', ':'), '', strip_tags($params['id'])));
if(empty($theme))
{
return DataReturn('主题名称有误', -1);
}
// 获取配置信息
$config_file = self::$old_path.DS.$theme.DS.'config.json';
if(!file_exists($config_file))
{
return DataReturn('主题配置文件不存在', -1);
}
$config = json_decode(file_get_contents($config_file), true);
if(empty($config))
{
return DataReturn('主题配置信息有误', -1);
}
// 目录不存在则创建
$new_dir = ROOT.'runtime'.DS.'data'.DS.'theme_appmini_package'.DS.$theme;
\base\FileUtil::CreateDir($new_dir);
// 复制包目录
$old_dir = self::$old_path.DS.$theme;
if(is_dir($old_dir))
{
if(\base\FileUtil::CopyDir($old_dir, $new_dir) != true)
{
return DataReturn('项目包复制失败', -2);
}
}
// 生成压缩包
$zip = new \base\ZipFolder();
if(!$zip->zip($new_dir.'.zip', $new_dir))
{
return DataReturn('压缩包生成失败', -100);
}
// 生成成功删除目录
\base\FileUtil::UnlinkDir($new_dir);
// 开始下载
if(\base\FileUtil::DownloadFile($new_dir.'.zip', $config['name'].'.zip'))
{
@unlink($new_dir.'.zip');
} else {
return DataReturn('下载失败', -100);
}
}
/**
* 获取小程序下载包数据列表
* @author Devil
* @blog http://gong.gg/
* @version 0.0.1
* @datetime 2017-05-10T10:24:40+0800
* @param [array] $params [输入参数]
*/
public static function DataList($params = [])
public static function DownloadDataList($params = [])
{
// 初始化
self::Init($params);
@ -111,7 +429,9 @@ class AppMiniService
self::Init($params);
// 配置内容
if(empty($params['app_mini_title']) || empty($params['app_mini_describe']))
$title = MyC('common_app_mini_'.self::$application_name.'_title');
$describe = MyC('common_app_mini_'.self::$application_name.'_describe');
if(empty($title) || empty($describe))
{
return DataReturn('配置信息不能为空', -1);
}
@ -135,8 +455,9 @@ class AppMiniService
\base\FileUtil::CreateDir(self::$new_path);
// 复制包目录
$old_dir = self::$old_path.DS.self::$default_theme;
$new_dir = self::$new_path.DS.date('YmdHis');
if(\base\FileUtil::CopyDir(self::$old_path, $new_dir) != true)
if(\base\FileUtil::CopyDir($old_dir, $new_dir) != true)
{
return DataReturn('项目包复制失败', -2);
}
@ -157,8 +478,8 @@ class AppMiniService
];
$replace = [
__MY_URL__,
$params['app_mini_title'],
$params['app_mini_describe'],
$title,
$describe,
config('shopxo.currency_symbol'),
];
$status = file_put_contents($new_dir.DS.'app.js', str_replace($search, $replace, file_get_contents($new_dir.DS.'app.js')));
@ -168,7 +489,7 @@ class AppMiniService
}
// app.json
$status = file_put_contents($new_dir.DS.'app.json', str_replace(['{{application_title}}'], [$params['app_mini_title']], file_get_contents($new_dir.DS.'app.json')));
$status = file_put_contents($new_dir.DS.'app.json', str_replace(['{{application_title}}'], [$title], file_get_contents($new_dir.DS.'app.json')));
if($status === false)
{
return DataReturn('基础配置替换失败', -4);

View File

@ -28,6 +28,19 @@ class ThemeService
// 排除的文件后缀
private static $exclude_ext = ['php'];
/**
* 默认主题标识符
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-20
* @desc description
*/
public static function DefaultTheme()
{
return MyC('common_default_theme', 'default', true);
}
/**
* 获取模板列表
* @author Devil
@ -48,7 +61,7 @@ class ThemeService
$default_preview = __MY_PUBLIC_URL__.'static'.DS.'common'.DS.'images'.DS.'default-preview.jpg';
while(($temp_file = readdir($dh)) !== false)
{
if(in_array($temp_file, ['.', '..', 'index.html']))
if(substr($temp_file, 0, 1) == '.' || in_array($temp_file, ['index.html']))
{
continue;
}
@ -203,9 +216,18 @@ class ThemeService
*/
public static function ThemeDelete($params = [])
{
if(empty($params['id']))
// 请求参数
$p = [
[
'checked_type' => 'empty',
'key_name' => 'id',
'error_msg' => '模板id有误',
],
];
$ret = ParamsChecked($params, $p);
if($ret !== true)
{
return DataReturn('模板id有误', -1);
return DataReturn($ret, -1);
}
// 防止路径回溯
@ -221,11 +243,8 @@ class ThemeService
return DataReturn('系统模板不能删除', -2);
}
// 默认主题
$theme = MyC('common_default_theme', 'default', true);
// 不能删除正在使用的主题
if($theme == $id)
if(self::DefaultTheme() == $id)
{
return DataReturn('不能删除正在使用的主题', -2);
}

View File

@ -80,6 +80,7 @@ return [
'public_host' => $cdn_public_host,
// 应用商店地址
'website_url' => 'https://shopxo.net/',
'store_url' => 'https://store.shopxo.net/',
'store_payment_url' => 'https://store.shopxo.net/payment.html',
'store_theme_url' => 'https://store.shopxo.net/theme.html',

File diff suppressed because one or more lines are too long

View File

@ -404,5 +404,26 @@ class Images
}
return '';
}
/**
* 图片转base64
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-20
* @desc description
* @param [string] $image_file [图片地址不支持url形式]
*/
public function ImageToBase64($image_file)
{
$content = '';
if(file_exists($image_file))
{
$info = getimagesize($image_file);
$image_data = fread(fopen($image_file, 'r'), filesize($image_file));
$content = 'data:'.$info['mime'].';base64,'.chunk_split(base64_encode($image_data));
}
return $content;
}
}
?>

View File

@ -0,0 +1,18 @@
/**
* 列表
*/
.am-gallery-item-bottom {
background: #e6e6e6;
}
.am-gallery-desc * {
font-size: 12px;
}
.am-gallery-item:hover {
border: 1px solid #f60;
}
.theme-active {
border: 3px solid #5eb95e !important;
}
.am-gallery-title .submit-delete {
color:#C13932 !important;
}

View File

@ -574,4 +574,21 @@ table.am-table .am-btn-danger:hover {
*/
.am-alert .am-form-group:last-child {
border-bottom: 0;
}
/**
* 二级导航
*/
.second-nav {
background: #90b9ff;
}
.second-nav li a {
color: #fff;
}
.second-nav > li > a:hover {
font-weight: bold;
background-color: transparent;
}
.second-nav li.am-active a {
background-color: #1cc09f !important;
}

View File

@ -1,5 +1,18 @@
.am-gallery-item-bottom { background: #e6e6e6; padding: 5px 8px; }
.am-gallery-desc * { font-size: 12px; }
.am-gallery-item:hover { border: 1px solid #f60; }
.theme-active { border: 3px solid #5eb95e !important; }
.am-gallery-title .submit-delete { color:#C13932 !important; }
/**
* 列表
*/
.am-gallery-item-bottom {
background: #e6e6e6;
}
.am-gallery-desc * {
font-size: 12px;
}
.am-gallery-item:hover {
border: 1px solid #f60;
}
.theme-active {
border: 3px solid #5eb95e !important;
}
.am-gallery-title .submit-delete {
color:#C13932 !important;
}

View File

@ -0,0 +1,38 @@
$(function()
{
// 模板切换
$('.select-theme').on('click', function()
{
var theme = $(this).data('theme');
if(!$(this).parent().hasClass('theme-active'))
{
var $this = $(this);
if(theme != undefined)
{
// ajax请求
$.ajax({
url:$('.data-list').data('select-url'),
type:'POST',
dataType:"json",
timeout:10000,
data:{"theme":theme, "nav_type":$('.data-list').data('nav-type')},
success:function(result)
{
if(result.code == 0)
{
$('.am-gallery-item').removeClass('theme-active');
$this.parent().addClass('theme-active');
Prompt(result.msg, 'success');
} else {
Prompt(result.msg);
}
},
error:function()
{
Prompt('服务器错误');
}
});
}
}
});
});

View File

@ -15,7 +15,7 @@ $(function()
type:'POST',
dataType:"json",
timeout:10000,
data:{"common_default_theme":theme},
data:{"theme":theme},
success:function(result)
{
if(result.code == 0)

View File

@ -0,0 +1,6 @@
{
"name":"默认主题",
"ver":"1.9.1",
"author":"Devil",
"home":"https://shopxo.net/"
}

View File

Before

Width:  |  Height:  |  Size: 203 B

After

Width:  |  Height:  |  Size: 203 B

View File

Before

Width:  |  Height:  |  Size: 378 KiB

After

Width:  |  Height:  |  Size: 378 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 822 B

After

Width:  |  Height:  |  Size: 822 B

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Some files were not shown because too many files have changed in this diff Show More