Commit 595ca68f authored by luoboss's avatar luoboss
Browse files

新增应用插件开发工具

修复弹窗在table中样式异常的问题。
修复微信公众号登录账号与系统的账号审核设置机制不一致的问题。
修复微信公众号登录账号时,选择直接登录没有选择默认客户分组的问题。
修复手机访问后台,工单发起转派获取客服成员异常的问题。
修复前台登录注册相关页面中,关于密码长度的提示指引异常问题。
修复我的工单不显示工单状态的问题。
应用插件注册事件支持占位符。
应用插件补充install()方法。以便应用在首次安装时,部署初始化的必要文件。
控制器增加应用插件URL生成方法pluginUrl()。
应用插件控制器按照分组目录形式创建、运行。
parent d8410e65
No related merge requests found
Showing with 261 additions and 24 deletions
+261 -24
......@@ -240,7 +240,8 @@ class Login extends \Core\Controller\Controller {
$param['member_email'] = "{$randomAccount}@default.wx";
$param['member_account'] = "wx_{$randomAccount}";
$param['member_password'] = md5(\Model\Extra::getOnlyNumber());//随机写入一些字符,随机帐号无法使用
$param['member_status'] = \Core\Func\CoreFunc::$param['system']['member_review'];
$param['member_status'] = \Core\Func\CoreFunc::$param['system']['member_review'] == 2 ? 0 : \Core\Func\CoreFunc::$param['system']['member_review'];
$param['member_organize_id'] = 1 ; //默认客户分组为 1
$param['member_createtime'] = time();
$memberID = $this->db('member')->insert($param);
......
......@@ -64,9 +64,17 @@ class Application extends \Core\Controller\Controller {
*/
public function install(){
$plugin = $this->isP('name', '请提交您要安装的应用');
$enName = $this->isP('enname', '请提交应用的名称');
$this->downloadPlugin($plugin);
//获取插件初始化类命名空间。
$pluginInitNameSpace = "\\Plugin\\{$enName}\\Init";
$pluginInit = new $pluginInitNameSpace();
//执行应用插件预设的安装事件
$pluginInit->install();
$this->success('应用安装完毕');
}
......
......@@ -379,6 +379,18 @@ class Controller {
return \Core\Func\CoreFunc::url($controller, $param);
}
/**
* 插件URL快速生成
* @param array $param
* @param null $group
* @param bool $filterHtmlSuffix
* @return type
*/
protected function pluginUrl(array $param, $group = NULL, $filterHtmlSuffix = false){
$group = empty($group) ? GROUP : $group;
return $this->url("{$group}-Application-Plugin", $param, $filterHtmlSuffix);
}
/**
* restful方法
*/
......
......@@ -39,7 +39,7 @@ class Plugin{
continue;
}
foreach ($item[$type] as $action => $auth){
if(strcmp($auth, GROUP.'-'.MODULE.'-'.ACTION) !== 0){
if(strcmp($this->placeholder($auth), GROUP.'-'.MODULE.'-'.ACTION) !== 0){
return false;
}
......@@ -52,6 +52,15 @@ class Plugin{
}
/**
* 快速处理路由的占位符
* @param $str 需要处理的路由规则
* @return mixed
*/
private static function placeholder($str){
return str_replace([':g', ':m', ':a'], [GROUP, MODULE, ACTION], $str);
}
/**
* 注册插件
*/
......
......@@ -35,7 +35,13 @@ interface PluginImplements{
public function remove();
/**
* 升级插件
* 安装插件执行的事件
* @return mixed
*/
public function install();
/**
* 升级插件执行的事件
* @return mixed
*/
public function upgrade();
......
......@@ -86,11 +86,13 @@ class Label {
/**
* 插件URL快速生成
* @param array $param
* @param null $group
* @param bool $filterHtmlSuffix
* @return type
*/
public function pluginUrl(array $param, $filterHtmlSuffix = false){
return $this->url(GROUP.'-Application-Plugin', $param, $filterHtmlSuffix);
public function pluginUrl(array $param, $group = NULL, $filterHtmlSuffix = false){
$group = empty($group) ? GROUP : $group;
return $this->url("{$group}-Application-Plugin", $param, $filterHtmlSuffix);
}
/**
......
......@@ -8,7 +8,7 @@ namespace Expand;
class dingtalk {
public $access_token = '';
private $AgentId, $AppKey, $AppSecret, $error;
public $AgentId, $AppKey, $AppSecret, $error;
public function __construct() {
$dingtalkSetting = json_decode(\Core\Func\CoreFunc::$param['system']['dingtalk'], true);
......
......@@ -8,7 +8,7 @@ namespace Expand;
class weixin {
public $access_token = '', $error;
private $appID, $appsecret;
public $appID, $appsecret;
public function __construct() {
$weixin_api = json_decode(\Core\Func\CoreFunc::$param['system']['weixin_api'], true);
......
......@@ -8,7 +8,7 @@ namespace Expand;
class weixinWork {
public $access_token = '';
private $corpid, $AgentId, $Secret, $error;
public $corpid, $AgentId, $Secret, $error;
public function __construct() {
$weixinWork_api = json_decode(\Core\Func\CoreFunc::$param['system']['weixinWork_api'], true);
......
......@@ -24,6 +24,17 @@ class zip {
*/
private $installFile = [];
/**
* 打包的目录文件列表
* @var array
*/
private $packageFile = [];
/**
* 解压文件
* @param $zipfile
* @return array|bool
*/
public function unzip($zipfile) {
$zip = zip_open($zipfile);
if (!is_resource($zip)) {
......@@ -96,4 +107,46 @@ class zip {
}
}
/**
* 打包目录
* @param $zipName 打包的文件名称
* @param $path 要打包的目录
*/
public function package($zipName, $path){
$this->packageFile = [];
$this->recursion($path);
$zip = new \ZipArchive();
$zip->open($zipName, \ZipArchive::CREATE); //打开压缩包
foreach ($this->packageFile as $item){
if(is_dir($item)){
$zip->addEmptyDir(str_replace(PES_CORE, '', $item));
}else{
$zip->addFile($item, str_replace(PES_CORE, '', $item));
}
}
$zip->close();
}
/**
* 递归指定目录所有文件信息
* @param $dirName
*/
private function recursion($dirName){
$this->packageFile[] = $dirName;
if ($handle = opendir("$dirName")) {
while (false !== ($item = readdir($handle))) {
if ($item != "." && $item != "..") {
if (is_dir("{$dirName}/{$item}")) {
$this->recursion("{$dirName}/{$item}");
} else {
$this->packageFile[] = "{$dirName}/{$item}";
}
}
}
closedir($handle);
}
}
}
\ No newline at end of file
<?php
/**
* @author PESCMS
* @copyright ©PESCMS
* @license https://www.pescms.com/article/view/-1.html
*/
if (substr(php_sapi_name(), 0, 3) != 'cli') {
exit("本功能只能在cli模式下允许");
}
defined('PES_CORE') or define('PES_CORE', __DIR__ . '/');
function msg($content){
return PHP_EOL.$content.PHP_EOL.PHP_EOL;
}
if (empty($argv) || count($argv) < 2) {
die(msg("欢迎使用PESCMS应用插件开发工具." . PHP_EOL . "输入-h -help获取更多帮助"));
}
$command = [
'-c' => 'create',
'-p' => 'package',
];
if (in_array($argv['1'], ['-h', '-help'])) {
$action = 'help';
} elseif (empty($command[$argv['1']])){
die(msg('未知参数,请输入-h 或者 -help 查看帮助信息.'));
}elseif (empty($argv['2'])){
die(msg(" {$argv['1']} 参数不完整,请输入-h 或者 -help 查看帮助信息." ));
}else{
$action = $command[$argv['1']];
}
class PluginDevelop {
/**
* 帮助文档
*/
public function help() {
$doc = [
'PESCMS应用插件开发工具支持如下指令:',
' -h, -help 查看帮助信息',
" -c <应用名称> 快速创建一个新的应用插件.",
" -p <应用名称> 将当前开发的应用进行打包."
];
die(msg(implode(PHP_EOL, $doc
)));
}
/**
* 创建一个新的应用插件
*/
public function create($name) {
$initPath = [PES_CORE."Plugin/{$name}", PES_CORE."Public/Plugin/{$name}", PES_CORE."Public/Plugin/{$name}/view"];
foreach ($initPath as $item){
if(is_dir($item) == false && mkdir($item) == false ){
die(msg("创建'{$name}'应用插件{$item}目录失败,请检查是否有写入权限。"));
}
touch("{$item}/index.html");
}
$this->createIniFile($name, $initPath['0']);
$this->creditPHPInitFile($name, $initPath['0']);
die(msg("应用插件'{$name}'已成功创建!马上开始您的开发之旅吧。"));
}
/**
* 写入应用插件的ini文件信息
* @param $name 应用名称
* @param $patch 应用目录
*/
private function createIniFile($name, $path){
$iniInfo = ['[plugin]', 'version', 'name', 'enname', 'content', 'author', 'website', 'GROUP', 'status'];
$iniFopen = fopen("{$path}/plugin.ini", 'w');
$str = '';
foreach ($iniInfo as $key => $item){
if($key == 0){
$str .= $item.PHP_EOL;
}elseif ($item == 'enname'){
$str .= "{$item} = {$name}".PHP_EOL;
}elseif ($item == end($iniInfo)){
$str .= "{$item} = disabled".PHP_EOL;
}else{
$str .= "{$item} = ".PHP_EOL;
}
}
fwrite($iniFopen, $str);
fclose($iniFopen);
}
/**
* 创建应用插件Init.php
* @param $name 应用名称
* @param $patch 应用目录
*/
private function creditPHPInitFile($name, $patch){
$fileContent = [
'header' => [
'<?php',
"namespace Plugin\\{$name};",
'use \Core\Plugin\PluginController,',
' \Core\Plugin\PluginImplements;',
'',
'class Init extends PluginController implements PluginImplements {',
],
'content' => [
'option',
'enabled',
'disabled',
'remove',
'install',
'upgrade'
],
'footer' => '}'
];
$fopen = fopen("{$patch}/Init.php", 'w');
fwrite($fopen, implode(PHP_EOL, $fileContent['header']).PHP_EOL);
foreach ($fileContent['content'] as $item){
fwrite($fopen, PHP_EOL." public function {$item}() {}".PHP_EOL);
}
fwrite($fopen, PHP_EOL.$fileContent['footer']);
}
/**
* 打包应用插件
*/
public function package($name) {
require_once __DIR__.'/Expand/zip.php';
$zip = new \Expand\zip();
$zip->package("{$name}.zip", PES_CORE."Plugin/{$name}");
$zip->package("{$name}.zip", PES_CORE."Public/Plugin/{$name}");
die(msg("应用插件'{$name}'已完成打包!打包文件'{$name}'.zip存放在".PES_CORE."目录下。"));
}
}
$init = new PluginDevelop();
$init->$action(empty($argv['2']) ? '' : $argv['2']);
\ No newline at end of file
......@@ -18,14 +18,14 @@
<div class="am-form-group">
<label class="am-u-sm-2 am-form-label">管理员密码:</label>
<div class="am-u-sm-10">
<input type="text" name="passwd" placeholder="管理员密码" minlength="6" required>
<input type="text" name="passwd" placeholder="管理员密码" minlength="6" data-am-popover="{trigger:'focus', theme: 'danger sm', content: '请输入不小于6位数的密码'}" required>
</div>
</div>
<div class="am-form-group">
<label class="am-u-sm-2 am-form-label">再次确认密码:</label>
<div class="am-u-sm-10">
<input type="text" name="repasswd" placeholder="再次确认密码" minlength="6" required>
<input type="text" name="repasswd" placeholder="再次确认密码" minlength="6" data-am-popover="{trigger:'focus', theme: 'danger sm', content: '请输入不小于6位数的密码'}" required>
</div>
</div>
......
1.3.2
\ No newline at end of file
1.3.3
\ No newline at end of file
<?php include THEME_PATH . '/header.php'; ?>
<?php include THEME_PATH .'/Topbar.php'; ?>
<div class="am-g">
<div class="am-g am-margin-top">
<div class="am-u-sm-12 am-u-sm-centered">
<div class="am-panel am-panel-default">
<div class="am-panel-bd">
......
......@@ -9,7 +9,7 @@
</div>
<div class="loginFlow">
<input type="text" class="pes-login-input" name="verify" placeholder="验证码" maxlength="<?= $system['verifyLength'] ?>" required>
<input type="text" class="pes-login-input" name="verify" placeholder="验证码" maxlength="<?= $system['verifyLength'] ?>" autocomplete="off" required>
</div>
</div>
......
......@@ -9,7 +9,7 @@
</div>
<div class="loginFlow">
<input type="password" name="password" class="pes-login-input" placeholder="登录密码" minlength="6" required="required">
<input type="password" name="password" class="pes-login-input" placeholder="登录密码" minlength="6" data-am-popover="{trigger:'focus', theme: 'danger sm', content: '请输入不小于6位数的登录密码'}" required="required">
</div>
<?php if(json_decode($system['login_verify'])[0] == '1'): ?>
......@@ -20,7 +20,7 @@
</div>
<div class="loginFlow">
<input type="text" class="pes-login-input" name="verify" placeholder="验证码" maxlength="<?= $system['verifyLength'] ?>" required>
<input type="text" class="pes-login-input" name="verify" placeholder="验证码" maxlength="<?= $system['verifyLength'] ?>" autocomplete="off" required>
</div>
</div>
......
<div class="loginFlow">
<input type="password" name="passwd" class="pes-login-input" placeholder="密码" minlength="6" required="required">
<input type="password" name="passwd" class="pes-login-input" placeholder="密码" minlength="6" data-am-popover="{trigger:'focus', theme: 'danger sm', content: '请输入不小于6位数的密码'}" required="required">
</div>
<div class="loginFlow">
<input type="password" name="repasswd" class="pes-login-input" placeholder="确认密码" minlength="6" required="required">
<input type="password" name="repasswd" class="pes-login-input" placeholder="确认密码" minlength="6" data-am-popover="{trigger:'focus', theme: 'danger sm', content: '请输入不小于6位数的密码'}" required="required">
</div>
<div class="login-verify">
......@@ -13,7 +13,7 @@
</div>
<div class="loginFlow">
<input type="text" class="pes-login-input" name="verify" placeholder="验证码" maxlength="<?= $system['verifyLength'] ?>" required>
<input type="text" class="pes-login-input" name="verify" placeholder="验证码" maxlength="<?= $system['verifyLength'] ?>" autocomplete="off" required>
</div>
</div>
......
......@@ -18,11 +18,11 @@
<div class="loginFlow">
<input type="password" name="password" class="pes-login-input" placeholder="密码" minlength="6" required="required">
<input type="password" name="password" class="pes-login-input" placeholder="密码" minlength="6" data-am-popover="{trigger:'focus', theme: 'danger sm', content: '请输入不小于6位数的密码'}" required="required">
</div>
<div class="loginFlow">
<input type="password" name="repassword" class="pes-login-input" placeholder="确认密码" minlength="6" required="required">
<input type="password" name="repassword" class="pes-login-input" placeholder="确认密码" minlength="6" data-am-popover="{trigger:'focus', theme: 'danger sm', content: '请输入不小于6位数的密码'}" required="required">
</div>
<div class="login-verify">
......@@ -31,7 +31,7 @@
<img src="<?= $label->url('Index-verify') ?>" class="refresh-verify am-text-center">
</div>
<div class="loginFlow">
<input type="text" class="pes-login-input login-verify" name="verify" placeholder="验证码" maxlength="<?= $system['verifyLength'] ?>">
<input type="text" class="pes-login-input login-verify" name="verify" placeholder="验证码" maxlength="<?= $system['verifyLength'] ?>" autocomplete="off" required>
</div>
</div>
......
......@@ -21,7 +21,7 @@
</div>
<div class="loginFlow">
<input type="password" name="password" class="pes-login-input" placeholder="密码" required="required">
<input type="password" name="password" class="pes-login-input" placeholder="密码" data-am-popover="{trigger:'focus', theme: 'danger sm', content: '请输入不小于6位数的密码'}" required="required">
</div>
<button type="submit" class="am-btn am-btn-primary am-radius am-btn-sm am-margin-top am-btn-block">提交</button>
......
......@@ -96,14 +96,14 @@
<?php foreach ($chat as $value): ?>
<li class="<?= $value['user_id'] == '-1' ? 'am-text-gray am-text-gray-background' : '' ?> ">
<div class="am-g">
<div class="am-u-sm-1">
<div class="am-u-sm-2 am-u-lg-1">
<?php if($value['user_id'] == '-1'): ?>
<i class="am-icon-btn am-primary am-icon-user"></i>
<?php else: ?>
<i class="am-icon-btn am-danger am-icon-slideshare"></i>
<?php endif; ?>
</div>
<div class="am-u-sm-11">
<div class="am-u-sm-10 am-u-lg-11">
<div class="am-block am-nbfc">
<?= $value['user_id'] == '-1' ? (empty($member) ? '匿名用户 : ' : "{$member['member_name']} : " ) : "{$value['user_name']} : " ?><?= $label->xss(htmlspecialchars_decode($value['ticket_chat_content'])) ?>
</div>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment