瀏覽代碼

add: 增加命令行,更新2021到2022之类的

joe 3 年之前
父節點
當前提交
c1b896c30c

+ 1 - 0
app/admin/controller/store/StoreProduct.php

@@ -146,6 +146,7 @@ class StoreProduct extends AuthController
         $luckies = get_luckies();
         $this->assign('lucky_id', json_encode($luckies));
         $this->assign('lucky_spec_name', Config::get('activity.lucky_spec_name') );
+        $this->assign('lucky_name', get_luck_name());
         return $this->fetch();
     }
 

+ 8 - 0
app/admin/model/store/StoreProductAttr.php

@@ -6,6 +6,7 @@
 
 namespace app\admin\model\store;
 
+use Config;
 use crmeb\basic\BaseModel;
 use crmeb\traits\ModelTrait;
 
@@ -147,4 +148,11 @@ class StoreProductAttr extends BaseModel
         return self::where('product_id', $productId)->select()->toArray();
     }
 
+    /**
+     * 
+     */
+    public static function getLuckyAttrs(string $attr_name) : array
+    {
+        return self::where('attr_name', $attr_name)->select()->toArray();
+    }
 }

+ 3 - 2
app/admin/view/store/store_product/create.php

@@ -895,6 +895,7 @@
     var type = {$type};
     var lucky_id = {$lucky_id};
     var lucky_spec_name = '{$lucky_spec_name}';
+    var lucky_name = '{$lucky_name}';
 
     new Vue({
         el: '#app',
@@ -1498,7 +1499,7 @@
                     return that.showMsg('请填选择商品轮播图');
                 }
                 if (is_lucky && that.formData.spec_type == 0) {
-                    return that.showMsg('幸运2021 必须为多规格');
+                    return that.showMsg($lucky_name + ' 必须为多规格');
                 }
                 if (that.formData.spec_type == 0) {
                     if (!that.formData.attr.pic) {
@@ -1545,7 +1546,7 @@
                             return true;
                         }
                     })) {
-                        return that.showMsg('非 幸运2021 使用了[幸运]规格');
+                        return that.showMsg('非 ' + lucky_name + ' 使用了[幸运]规格');
                     }
 
                     if (!that.formData.attrs.length) {

+ 44 - 20
app/common.php

@@ -14,6 +14,16 @@ use \think\facade\Log;
 
 // 应用公共文件
 
+// 通用预定义
+define('SHOW', 1);
+define('HIDE', 0);
+
+define('ENABLED', 1);
+define('DISABLED', 0);
+
+define('YES', 1);
+define('NO', 0);
+
 // 订单常量
 // 订单状态(-1 : 申请退款 -2 : 退货成功 0:待发货;1:待收货;2:已收货;3:待评价;-1:已退款)
 define('ORDER_REFUND_REQUSTED', -1);
@@ -87,7 +97,7 @@ function infolog($log)
 /**
  * 获取所有 幸运2021 活动及其子活动 ID 列表
  */
-function get_luckies(): Array 
+function get_luckies(): array
 {
     return [
         ThinkConf::get('activity.lucky_cate_id'),
@@ -96,15 +106,25 @@ function get_luckies(): Array
     ];
 }
 
+/**
+ * 根据配置拼接幸运活动完整名称
+ */
+function get_luck_name(): string
+{
+    $spec_name = ThinkConf::get('activity.lucky_spec_name');
+    $spec_items = ThinkConf::get('activity.lucky_spec_items');
+    return $spec_name . implode('', $spec_items);
+}
+
 /**
  * 获取 提现类型, 帐号,用于日志或者消息
  */
-function get_extract_name($extract): Array
+function get_extract_name($extract): array
 {
     if (!$extract || !isset($extract['extract_type'])) {
         return ['未知', ''];
     }
-    switch($extract['extract_type']) {
+    switch ($extract['extract_type']) {
         case 'weixin':
             return ['微信支付', $extract['wechat'] ?? ''];
         case 'alipay':
@@ -175,7 +195,8 @@ if (!function_exists('filter_emoji')) {
             function (array $match) {
                 return strlen($match[0]) >= 4 ? '' : $match[0];
             },
-            $str);
+            $str
+        );
         return $str;
     }
 }
@@ -190,11 +211,10 @@ if (!function_exists('str_middle_replace')) {
      */
     function str_middle_replace($string, $start, $end)
     {
-        $strlen = mb_strlen($string, 'UTF-8');//获取字符串长度
-        $firstStr = mb_substr($string, 0, $start, 'UTF-8');//获取第一位
-        $lastStr = mb_substr($string, -1, $end, 'UTF-8');//获取最后一位
+        $strlen = mb_strlen($string, 'UTF-8'); //获取字符串长度
+        $firstStr = mb_substr($string, 0, $start, 'UTF-8'); //获取第一位
+        $lastStr = mb_substr($string, -1, $end, 'UTF-8'); //获取最后一位
         return $strlen == 2 ? $firstStr . str_repeat('*', mb_strlen($string, 'utf-8') - 1) : $firstStr . str_repeat("*", $strlen - 2) . $lastStr;
-
     }
 }
 
@@ -257,7 +277,6 @@ if (!function_exists('make_path')) {
                 throw new \Exception($e->getMessage());
             return '无法创建文件夹,请检查您的上传目录权限:' . app()->getRootPath() . 'public' . DS . 'uploads' . DS . 'attach' . DS;
         }
-
     }
 }
 
@@ -318,7 +337,6 @@ if (!function_exists('set_http_type')) {
         }
         return $url;
     }
-
 }
 
 if (!function_exists('check_card')) {
@@ -377,9 +395,10 @@ if (!function_exists('check_phone')) {
      */
     function check_phone($phone)
     {
-        return preg_match( "/^1[3456789]\d{9}$/", $phone);
+        return preg_match("/^1[3456789]\d{9}$/", $phone);
     }
 }
+
 if (!function_exists('anonymity')) {
     /**
      * 匿名处理处理用户昵称
@@ -398,6 +417,7 @@ if (!function_exists('anonymity')) {
             return mb_substr($name, 0, 1, 'UTF-8') . str_repeat('*', $strLen - 1) . mb_substr($name, -1, 1, 'UTF-8');
     }
 }
+
 if (!function_exists('sort_list_tier')) {
     /**
      * 分级排序
@@ -630,7 +650,8 @@ if (!function_exists('array_unique_fb')) {
 }
 
 if (!function_exists('ts_of_day')) {
-    function ts_of_day($timestamp=null) {
+    function ts_of_day($timestamp = null)
+    {
         if ($timestamp == null) {
             $timestamp = time();
         }
@@ -640,20 +661,23 @@ if (!function_exists('ts_of_day')) {
 }
 
 if (!function_exists('mapped_implode')) {
-    function mapped_implode($glue, $array, $symbol='=') {
-        return implode($glue, array_map(
-                function($k, $v) use($symbol) {
+    function mapped_implode($glue, $array, $symbol = '=')
+    {
+        return implode(
+            $glue,
+            array_map(
+                function ($k, $v) use ($symbol) {
                     return $k . $symbol . $v;
                 },
                 array_keys($array),
                 array_values($array)
-                )
-            );
+            )
+        );
     }
 }
 
 if (!function_exists('async_call')) {
-    function async_call(string $className, array $classArgs, string $methodName, array $methodArgs) {
-        
+    function async_call(string $className, array $classArgs, string $methodName, array $methodArgs)
+    {
     }
-}
+}

+ 0 - 9
app/models/store/StoreService.php

@@ -12,15 +12,6 @@ namespace app\models\store;
 use crmeb\basic\BaseModel;
 use crmeb\traits\ModelTrait;
 
-define('SHOW', 1);
-define('HIDE', 0);
-
-define('ENABLED', 1);
-define('DISABLED', 0);
-
-define('YES', 1);
-define('NO', 0);
-
 /**
  * TODO 客服Model
  * Class StoreService

+ 1 - 1
config/activity.php

@@ -18,7 +18,7 @@ return [
     'clearrance_daily_opens' => [],
     // 幸运商品规格
     'lucky_spec_name' => '幸运',
-    'lucky_spec_items' => [20, 21],
+    'lucky_spec_items' => [20, 22],
     // 幸运活动 ID
     'lucky_cate_id' => 1,
     // 幸运活动番外A ID

+ 4 - 3
config/console.php

@@ -17,8 +17,9 @@ return [
     'user'     => null,
     // 指令定义
     'commands' => [
-        'workerman'=>\crmeb\command\Workerman::class,
-        'timer'=>\crmeb\command\Timer::class,
-        'task' =>\crmeb\command\Task::class,
+        'workerman' => \crmeb\command\Workerman::class,
+        'timer' => \crmeb\command\Timer::class,
+        'task' => \crmeb\command\Task::class,
+        'maintain' => \tw\command\Maintain::class,
     ],
 ];

+ 5 - 6
crmeb/command/Task.php

@@ -45,7 +45,7 @@ class Task extends Command
     {
         global $argv;
 
-        $argv[1] = $input->getArgument('status')?:'start';
+        $argv[1] = $input->getArgument('status') ?: 'start';
 
         if ($input->hasOption('d')) {
             $argv[2] = '-d';
@@ -69,12 +69,12 @@ class Task extends Command
     {
         $tube = Config::get('app.beanstalk_tube');
         Beanstalk::watch($tube);
-        while(true) {
+        while (true) {
             $job = Beanstalk::reserveWithTimeout(30);
             if (is_null($job)) {
                 continue;
             }
-            
+
             $executed = false;
             try {
                 $str_payload = $job->getData();
@@ -85,13 +85,13 @@ class Task extends Command
                     new AsyncSms(),
                 ];
 
-                foreach($asyncTasks as $t) {
+                foreach ($asyncTasks as $t) {
                     if ($t->getCmd() == $payload['cmd']) {
                         $retval = $t->exec($payload);
                         if (!$retval) {
                             warnlog('async task executed return false:' . $str_payload);
                         }
-                        infolog("task: $str_payload return:". json_encode($retval));
+                        infolog("task: $str_payload return:" . json_encode($retval));
                         $executed = true;
                     }
                 }
@@ -116,4 +116,3 @@ class Task extends Command
         echo 'task stopped';
     }
 }
-

+ 1 - 4
crmeb/command/Timer.php

@@ -8,7 +8,6 @@ use think\console\Input;
 use think\console\input\Argument;
 use think\console\input\Option;
 use think\console\Output;
-use think\facade\Log;
 use Workerman\Worker;
 
 class Timer extends Command
@@ -51,7 +50,7 @@ class Timer extends Command
     protected function execute(Input $input, Output $output)
     {
         $this->init($input, $output);
-        Worker::$pidFile = app()->getRootPath().'timer.pid';
+        Worker::$pidFile = app()->getRootPath() . 'timer.pid';
         $task = new Worker();
         $task->count = 1;
         event('Timer_6');
@@ -82,6 +81,4 @@ class Timer extends Command
             }
         });
     }
-
-
 }

+ 6 - 6
crmeb/command/Workerman.php

@@ -73,22 +73,22 @@ class Workerman extends Command
     protected function execute(Input $input, Output $output)
     {
         $server = $this->init($input, $output);
-        Worker::$pidFile = app()->getRootPath().'workerman.pid';
-        if(!$server || $server == 'admin'){
+        Worker::$pidFile = app()->getRootPath() . 'workerman.pid';
+        if (!$server || $server == 'admin') {
             var_dump('admin');
             //创建 admin 长连接服务
             $this->workerServer = new Worker($this->config['admin']['protocol'] . '://' . $this->config['admin']['ip'] . ':' . $this->config['admin']['port']);
             $this->workerServer->count = $this->config['admin']['serverCount'];
         }
 
-        if(!$server || $server == 'chat') {
+        if (!$server || $server == 'chat') {
             var_dump('chat');
             //创建 h5 chat 长连接服务
             $this->chatWorkerServer = new Worker($this->config['chat']['protocol'] . '://' . $this->config['chat']['ip'] . ':' . $this->config['chat']['port']);
             $this->chatWorkerServer->count = $this->config['chat']['serverCount'];
         }
 
-        if(!$server || $server == 'channel') {
+        if (!$server || $server == 'channel') {
             var_dump('channel');
             //创建内部通讯服务
             $this->channelServer = new Server($this->config['channel']['ip'], $this->config['channel']['port']);
@@ -103,7 +103,7 @@ class Workerman extends Command
 
     protected function bindHandle()
     {
-        if(!is_null($this->workerServer)){
+        if (!is_null($this->workerServer)) {
             $server = new WorkermanService($this->workerServer, $this->channelServer);
             // 连接时回调
             $this->workerServer->onConnect = [$server, 'onConnect'];
@@ -115,7 +115,7 @@ class Workerman extends Command
             $this->workerServer->onClose = [$server, 'onClose'];
         }
 
-        if(!is_null($this->chatWorkerServer)) {
+        if (!is_null($this->chatWorkerServer)) {
             $chatServer = new ChatService($this->chatWorkerServer, $this->channelServer);
             $this->chatWorkerServer->onConnect = [$chatServer, 'onConnect'];
             $this->chatWorkerServer->onMessage = [$chatServer, 'onMessage'];

+ 3 - 0
docs/gendoc.sh

@@ -1,3 +1,6 @@
 #!/usr/bin/env bash
+
+# pre-install is needed:
+# npm install -g apidoc
 apidoc -i ../app/api -o api_front
 apidoc -i ../app/admin -o api_admin

+ 285 - 0
tw/command/Maintain.php

@@ -0,0 +1,285 @@
+<?php
+
+namespace tw\command;
+
+use app\admin\model\store\StoreProductAttr;
+use app\admin\model\store\StoreProductAttrResult;
+use app\admin\model\store\StoreProductAttrValue;
+use app\models\store\StoreProductRule;
+use think\console\Command;
+use think\console\Input;
+use think\console\input\Argument;
+use think\console\Output;
+use \think\facade\Config;
+
+/**
+ * 维护命令,使用 nginx 帐号运行
+ * 
+ * sudo -u http php think maintain ***
+ */
+class Maintain extends Command
+{
+    const PREV_YEAR = 21;   // 活动的上一年标志。比如`幸运2021` 更新为 `幸运2022`,这个值就是 21
+
+    protected $NEW_YEAR;    // new year value
+    protected $LUCKY;
+
+    protected function configure()
+    {
+        $this->setName('maintain')
+            ->addArgument('category', Argument::REQUIRED, 'act|prod|trash|none')
+            ->setDescription('maintain some application data.');
+    }
+
+    protected function init(Input $input, Output $output)
+    {
+        global $argv;
+        $argv[1] = $input->getArgument('category') ?? 'none';
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        $category = $input->getArgument('category');
+        if (is_callable([$this, $category])) {
+            $this->$category();
+        } else {
+            console::log('bad argument ', $category);
+        }
+    }
+
+    /**
+     * 修改幸运 2021 后面的 2021
+     * 
+     * IMPORTANT:
+     * 修改步骤:
+     * 1. 修改 eb_store_category 中分类名称
+     * 2. 修改 congit/activity 中配置 
+     * 3. 执行 php think maintain act
+     */
+    protected function act()
+    {
+        console::log(__FUNCTION__);
+        $act_parts = Config::get('activity.lucky_spec_items', []);
+        if (is_array($act_parts) && count($act_parts) > 1) {
+            $this->NEW_YEAR = intval($act_parts[1]);
+        } else {
+            console::log('bad config: activity.lucky_spec_items. quit.');
+            return;
+        }
+        $act_name = Config::get('activity.lucky_spec_name', '');
+        $this->LUCKY = $act_name;
+
+        $this->_update_StoreProductAttr();
+        $this->_update_StoreProductAttrValue();
+        $this->_update_StoreProductAttrResult();
+        $this->_udpate_StoreProductRule();
+    }
+
+    /**
+     * 修改
+     */
+    private function _update_StoreProductAttr()
+    {
+        $rows = StoreProductAttr::getLuckyAttrs($this->LUCKY);
+
+        $changed = false;
+        foreach ($rows as &$row) {
+            $changed = false;
+            //
+            if (
+                is_array($row['attr_values']) &&
+                count($row['attr_values']) > 1 &&
+                intval($row['attr_values'][1]) == self::PREV_YEAR
+            ) {
+                $row['attr_values'][1] = $this->NEW_YEAR;
+                $changed = true;
+            }
+            // sql
+            if ($changed) {
+                try {
+                    $data['attr_values'] = implode(',', $row['attr_values']);
+                    // console::log($row);
+                    $ok = StoreProductAttr::where('product_id', $row['product_id'])
+                        ->where('attr_name', $row['attr_name'])
+                        ->update($data);
+                    if (!$ok) {
+                        console::log('execute sql failed.');
+                    }
+                } catch (\Exception $e) {
+                    console::log('execute sql exception:', $e->getMessage());
+                }
+            }
+        } // foreach
+        console::log('table StoreProductAttr updated.');
+    }
+
+    private function _update_StoreProductAttrValue()
+    {
+        $rows = StoreProductAttrValue::where('suk', 'like', '%' . self::PREV_YEAR . '%')->select()->toArray();
+        foreach ($rows as $row) {
+            $changed = false;
+
+            $suks = explode(',', $row['suk']);  // array
+            // replace 
+            for ($i = 0; $i < count($suks); $i++) {
+                if (intval($suks[$i]) == self::PREV_YEAR) {
+                    $suks[$i] = $this->NEW_YEAR;
+                    $changed = true;
+                }
+            }
+
+            if (!$changed) {
+                continue;
+            }
+
+            // $data['unique'] = sp_random_string(); //  $row['unique'];
+            $data['suk'] = implode(',', $suks); // string again
+            try {
+                $ok = StoreProductAttrValue::edit($data, $row['unique'], 'unique');
+                if (!$ok) {
+                    console::log('update StoreProductAttrValue failed.', $ok);
+                }
+            } catch (\Exception $e) {
+                console::log('update StoreProductAttrValue exception:', $e->getMessage());
+            }
+        }
+    }
+
+    private function _update_StoreProductAttrResult()
+    {
+        $rows = StoreProductAttrResult::where("1=1")->field('product_id,result')->select()->toArray();
+        $changed = false;
+        foreach ($rows as $row) {
+            $changed = false;
+            $result = json_decode($row['result'], true);
+
+            if (isset($result['attr']) && count($result['attr']) > 0) {
+                foreach ($result['attr'] as &$attr) {
+                    if (!isset($attr['value']) || $attr['value'] != $this->LUCKY) {
+                        continue;
+                    }
+
+                    if (isset($attr['detail']) && count($attr['detail']) > 0) {
+                        for ($i = 0; $i < count($attr['detail']); $i++) {
+                            // update
+                            if (intval($attr['detail'][$i]) == self::PREV_YEAR) {
+                                $attr['detail'][$i] = strval($this->NEW_YEAR);
+                                $changed = true;
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (isset($result['value']) && count($result['value']) > 0) {
+                foreach ($result['value'] as &$value) {
+                    foreach ($value as $k => $v) {
+                        if (substr($k, 0, 5) == 'value' && intval($v) == self::PREV_YEAR) {
+                            $value[$k] = strval($this->NEW_YEAR);
+                            $changed = true;
+                        } else if ($k == 'detail') {
+                            foreach ($v as $kk => $vv) {
+                                // update
+                                if ($kk == $this->LUCKY && intval($vv) == self::PREV_YEAR) {
+                                    $value[$k][$kk] = strval($this->NEW_YEAR);
+                                    $changed = true;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (!$changed) {
+                continue;
+            }
+
+            try {
+                $data['result'] = json_encode($result);
+                // console::log($row['product_id']);
+                $ok = StoreProductAttrResult::where('product_id', $row['product_id'])
+                    ->update($data);
+                if (!$ok) {
+                    console::log('sql execute error:', StoreProductAttrResult::getErrorInfo());
+                }
+            } catch (\Exception $e) {
+                console::log('exception:', $e->getMessage());
+            }
+        }
+    }
+
+    private function _udpate_StoreProductRule()
+    {
+        $rows = StoreProductRule::where('rule_name', 'like', '%' . $this->LUCKY . '%')->select()->toArray();
+        $changed = false;
+        foreach ($rows as $row) {
+            $changed = false;
+            $values = json_decode($row['rule_value'], true);
+            if (is_array($values)) {
+                foreach ($values as &$value) {
+                    if (!isset($value['value']) && $value['value'] != $this->LUCKY) {
+                        continue;
+                    }
+
+                    if (
+                        isset($value['detail']) &&
+                        is_array($value['detail']) &&
+                        count($value['detail']) > 0
+                    ) {
+
+                        for ($i = 0; $i < count($value['detail']); $i++) {
+                            if (intval($value['detail'][$i]) == self::PREV_YEAR) {
+                                $value['detail'][$i] = strval($this->NEW_YEAR);
+                                $changed = true;
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (!$changed) {
+                continue;
+            }
+
+            $data['rule_value'] = json_encode($values);
+
+            try {
+                console::log($values);
+                $ok = StoreProductRule::where('id', $row['id'])->update($data);
+                if (!$ok) {
+                    console::log('StoreProductRule failed:', StoreProductRule::getErrorInfo());
+                }
+            } catch (\Exception $e) {
+                console::log('StoreProductRule exception:', $e->getMessage());
+            }
+        }
+    }
+
+    /**
+     * 让一定时间之前的商品下架
+     */
+    protected function prod()
+    {
+        console::log(__FUNCTION__);
+    }
+
+    /**
+     * 删除过期日志等数据
+     */
+    protected function trash()
+    {
+    }
+
+    /**
+     * 备份数据库
+     * 
+     * 后台备份功能超出内存限制
+     */
+    protected function backup()
+    {
+    }
+
+    protected function none()
+    {
+    }
+}

+ 24 - 0
tw/command/console.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace tw\command;
+
+/**
+ * 向浏览器那样
+ * 
+ * print to console.
+ */
+class console
+{
+    public static function log(...$mix)
+    {
+        foreach ($mix as $v) {
+            // var_dump($v);
+            if (is_array($v)) {
+                print_r($v);
+            } else {
+                echo ($v);
+            }
+        }
+        echo PHP_EOL;
+    }
+}

+ 0 - 0
tw/console.php