├── .gitignore ├── LICENSE ├── README.md ├── app ├── admin │ ├── controller │ │ ├── Agentlevel.php │ │ ├── Builder.php │ │ ├── Cmsbanner.php │ │ ├── Cmscategory.php │ │ ├── Cmscontent.php │ │ ├── Cmsposition.php │ │ ├── Cmstag.php │ │ ├── Deliverylog.php │ │ ├── Index.php │ │ ├── Member.php │ │ ├── Memberaccount.php │ │ ├── Memberaddress.php │ │ ├── Memberlevel.php │ │ ├── Memberlog.php │ │ ├── Memberrecharge.php │ │ ├── Shippingarea.php │ │ ├── Shippingcom.php │ │ ├── Shopbrand.php │ │ ├── Shopcategory.php │ │ ├── Shopcouponlist.php │ │ ├── Shopcoupontype.php │ │ ├── Shopgoods.php │ │ ├── Shoporder.php │ │ ├── Shoporderaction.php │ │ ├── Shopordershipping.php │ │ └── Shoptag.php │ ├── logic │ │ └── OrderLogic.php │ └── view │ │ ├── index │ │ ├── dashbord.html │ │ └── dashbord2.html │ │ └── member │ │ └── tree.html ├── common │ ├── logic │ │ ├── AccountLogic.php │ │ ├── CartLogic.php │ │ ├── CouponLogic.php │ │ ├── GoodsLogic.php │ │ ├── MemberLogic.php │ │ ├── OrderLogic.php │ │ ├── PaymentLogic.php │ │ ├── RechargeLogic.php │ │ └── ShippingLogic.php │ └── model │ │ ├── AgentLevel.php │ │ ├── CmsBanner.php │ │ ├── CmsCategory.php │ │ ├── CmsContent.php │ │ ├── CmsPosition.php │ │ ├── CmsTag.php │ │ ├── DeliveryLog.php │ │ ├── Member.php │ │ ├── MemberAccount.php │ │ ├── MemberAddress.php │ │ ├── MemberCation.php │ │ ├── MemberLevel.php │ │ ├── MemberLog.php │ │ ├── MemberPayment.php │ │ ├── MemberRecharge.php │ │ ├── ShippingArea.php │ │ ├── ShippingAreaItem.php │ │ ├── ShippingCom.php │ │ ├── ShopBrand.php │ │ ├── ShopCart.php │ │ ├── ShopCategory.php │ │ ├── ShopCouponList.php │ │ ├── ShopCouponType.php │ │ ├── ShopGoods.php │ │ ├── ShopGoodsAttr.php │ │ ├── ShopGoodsSpec.php │ │ ├── ShopGoodsSpecPrice.php │ │ ├── ShopGoodsSpecValue.php │ │ ├── ShopOrder.php │ │ ├── ShopOrderAction.php │ │ ├── ShopOrderDelivery.php │ │ ├── ShopOrderGoods.php │ │ └── ShopTag.php ├── controller │ └── Index.php ├── functions.php ├── middleware │ └── StaticFile.php ├── model │ └── Test.php └── view │ └── index │ └── view.html ├── composer.json ├── composer.lock ├── config ├── app.php ├── autoload.php ├── bootstrap.php ├── container.php ├── database.php ├── dependence.php ├── event.php ├── exception.php ├── log.php ├── middleware.php ├── plugin │ ├── tpext │ │ ├── core │ │ │ ├── app.php │ │ │ ├── bootstrap.php │ │ │ └── middleware.php │ │ └── myadmin │ │ │ ├── app.php │ │ │ └── middleware.php │ └── webman │ │ └── event │ │ ├── app.php │ │ ├── bootstrap.php │ │ └── command.php ├── process.php ├── redis.php ├── route.php ├── server.php ├── session.php ├── static.php ├── thinkcache.php ├── thinkorm.php ├── translation.php └── view.php ├── extend ├── cooladmin │ ├── LICENSE.txt │ ├── README.md │ ├── admin │ │ └── view │ │ │ └── index │ │ │ ├── index.html │ │ │ └── login.html │ ├── assets │ │ ├── css │ │ │ ├── index.css │ │ │ ├── index.css.map │ │ │ ├── index.scss │ │ │ ├── login.css │ │ │ ├── login.css.map │ │ │ ├── login.scss │ │ │ └── readme.md │ │ ├── icon │ │ │ └── logo │ │ │ │ └── silder-simple.png │ │ ├── js │ │ │ ├── index.js │ │ │ └── tpextbuilder.js │ │ ├── lib │ │ │ ├── axios.min.js │ │ │ ├── index.js │ │ │ ├── theme-chalk │ │ │ │ ├── fonts │ │ │ │ │ ├── element-icons.ttf │ │ │ │ │ └── element-icons.woff │ │ │ │ └── index.css │ │ │ └── vue.min.js │ │ └── theme │ │ │ ├── black.css │ │ │ ├── blue.css │ │ │ ├── fonts │ │ │ ├── element-icons.ttf │ │ │ └── element-icons.woff │ │ │ ├── green.css │ │ │ └── purple.css │ └── common │ │ └── Resource.php ├── extdemo │ ├── LICENSE.txt │ ├── README.md │ ├── admin │ │ ├── controller │ │ │ └── Extdemo.php │ │ └── model │ │ │ └── Extdemo.php │ ├── assets │ │ ├── css │ │ │ └── test.css │ │ └── js │ │ │ └── test.js │ ├── common │ │ └── Module.php │ ├── config.php │ └── data │ │ ├── install.sql │ │ └── uninstall.sql ├── hplusadmin │ ├── LICENSE.txt │ ├── README.md │ ├── admin │ │ └── view │ │ │ └── index │ │ │ ├── index.html │ │ │ └── login.html │ ├── assets │ │ ├── css │ │ │ ├── login.min.css │ │ │ ├── patterns │ │ │ │ ├── header-profile-skin-1.png │ │ │ │ ├── header-profile-skin-3.png │ │ │ │ ├── header-profile.png │ │ │ │ └── shattered.png │ │ │ └── style.min.css │ │ ├── img │ │ │ └── login-background.jpg │ │ └── js │ │ │ ├── contabs.min.js │ │ │ ├── content.min.js │ │ │ ├── hplus.min.js │ │ │ └── plugins │ │ │ ├── metisMenu │ │ │ └── jquery.metisMenu.js │ │ │ └── slimscroll │ │ │ └── jquery.slimscroll.min.js │ └── common │ │ └── Resource.php └── myadmindata │ ├── LICENSE.txt │ ├── README.md │ ├── common │ └── Module.php │ └── data │ ├── install.sql │ └── uninstall.sql ├── process └── Monitor.php ├── public ├── 404.html ├── favicon.ico ├── linux.sh └── windows.bat ├── runtime ├── .gitignore ├── logs │ └── .gitignore └── views │ └── .gitignore ├── start.php ├── support ├── Plugin.php ├── Request.php ├── Response.php ├── bootstrap.php └── helpers.php └── windows.php /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /.vscode 3 | /vendor 4 | *.log 5 | .env 6 | /tests/tmp 7 | /tests/.phpunit.result.cache 8 | 9 | *.bak 10 | .env 11 | .DS_Store 12 | images 13 | public/uploads/ 14 | public/static/ 15 | public/assets/ 16 | extend/*.git/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 walkor and contributors (see https://github.com/walkor/webman/contributors) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/admin/controller/Agentlevel.php: -------------------------------------------------------------------------------- 1 | dataModel = new LevelModel; 27 | $this->pageTitle = '代理等级'; 28 | $this->sortOrder = 'level asc'; 29 | $this->selectSearch = 'name'; 30 | } 31 | 32 | protected function filterWhere() 33 | { 34 | $searchData = request()->get(); 35 | 36 | $where = []; 37 | 38 | if (!empty($searchData['name'])) { 39 | $where[] = ['name', 'like', '%' . $searchData['name'] . '%']; 40 | } 41 | 42 | return $where; 43 | } 44 | 45 | /** 46 | * 构建搜索 47 | * 48 | * @return void 49 | */ 50 | protected function buildSearch() 51 | { 52 | $search = $this->search; 53 | $search->text('name', '名称', 3)->maxlength(20); 54 | } 55 | 56 | /** 57 | * 构建表格 58 | * 59 | * @return void 60 | */ 61 | protected function buildTable(&$data = []) 62 | { 63 | $table = $this->table; 64 | 65 | $table->show('id', 'ID'); 66 | $table->text('name', '名称')->autoPost(); 67 | $table->text('level', '等级')->autoPost('', true)->getWrapper()->addStyle('width:150px'); 68 | $table->show('member_count', '人数统计'); 69 | $table->show('description', '描述'); 70 | $table->show('create_time', '添加时间')->getWrapper()->addStyle('width:150px'); 71 | $table->show('update_time', '更新时间')->getWrapper()->addStyle('width:150px'); 72 | } 73 | 74 | /** 75 | * 构建表单 76 | * 77 | * @param boolean $isEdit 78 | * @param array $data 79 | */ 80 | protected function buildForm($isEdit, &$data = []) 81 | { 82 | $form = $this->form; 83 | 84 | $form->text('name', '名称'); 85 | $form->number('level', '等级'); 86 | $form->textarea('description', '描述'); 87 | 88 | if ($isEdit) { 89 | $form->show('member_count', '人数统计'); 90 | $form->show('create_time', '添加时间'); 91 | $form->show('update_time', '更新时间'); 92 | } 93 | } 94 | 95 | /** 96 | * 保存数据 97 | * 98 | * @param integer $id 99 | * @return void 100 | */ 101 | private function save($id = 0) 102 | { 103 | $data = request()->only([ 104 | 'name', 105 | 'level', 106 | 'description', 107 | ], 'post'); 108 | 109 | $result = $this->validate($data, [ 110 | 'name|名称' => 'require', 111 | 'level|等级' => 'require|number' 112 | ]); 113 | 114 | if (true !== $result) { 115 | 116 | $this->error($result); 117 | } 118 | 119 | return $this->doSave($data, $id); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /app/admin/controller/Cmsbanner.php: -------------------------------------------------------------------------------- 1 | dataModel = new BannerModel; 34 | $this->positionModel = new CmsPosition; 35 | $this->pageTitle = '广告管理'; 36 | $this->enableField = 'is_show'; 37 | $this->pagesize = 6; 38 | 39 | $this->selectSearch = 'title'; 40 | $this->selectFields = 'id,title'; 41 | $this->selectTextField = 'title'; 42 | 43 | $this->indexWith = ['position']; 44 | } 45 | 46 | protected function filterWhere() 47 | { 48 | $searchData = request()->get(); 49 | 50 | $where = []; 51 | if (!empty($searchData['title'])) { 52 | $where[] = ['title', 'like', '%' . $searchData['title'] . '%']; 53 | } 54 | 55 | if (!empty($searchData['position_id'])) { 56 | $where[] = ['position_id', '=', $searchData['position_id']]; 57 | } 58 | 59 | return $where; 60 | } 61 | 62 | /** 63 | * 构建搜索 64 | * 65 | * @return void 66 | */ 67 | protected function buildSearch() 68 | { 69 | $search = $this->search; 70 | 71 | $search->text('title', '标题', 3)->maxlength(20); 72 | $search->select('position_id', '位置', 3)->optionsData($this->positionModel->select()); 73 | } 74 | 75 | /** 76 | * 构建表格 77 | * 78 | * @return void 79 | */ 80 | protected function buildTable(&$data = []) 81 | { 82 | $table = $this->table; 83 | 84 | $table->show('id', 'ID'); 85 | $table->image('image', '图片')->thumbSize(70, 70); 86 | $table->text('title', '标题')->autoPost()->getWrapper()->addStyle('max-width:200px'); 87 | $table->show('position.name', '位置'); 88 | $table->show('description', '摘要')->default('暂无')->getWrapper()->addStyle('max-width:200px'); 89 | $table->show('link', '链接'); 90 | $table->text('sort', '排序')->autoPost()->getWrapper()->addStyle('max-width:100px'); 91 | $table->switchBtn('is_show', '显示')->default(1)->autoPost(); 92 | $table->show('create_time', '添加时间')->getWrapper()->addStyle('width:180px'); 93 | $table->show('update_time', '修改时间')->getWrapper()->addStyle('width:180px'); 94 | 95 | $table->sortable('id,sort'); 96 | 97 | $table->getToolbar() 98 | ->btnAdd() 99 | ->btnEnableAndDisable('显示', '隐藏') 100 | ->btnDelete() 101 | ->btnRefresh(); 102 | 103 | $table->getActionbar() 104 | ->btnEdit() 105 | ->btnDelete(); 106 | } 107 | 108 | /** 109 | * 构建表单 110 | * 111 | * @param boolean $isEdit 112 | * @param array $data 113 | */ 114 | protected function buildForm($isEdit, &$data = []) 115 | { 116 | $form = $this->form; 117 | 118 | $form->text('title', '标题')->required()->maxlength(55); 119 | $form->select('position_id', '位置')->required()->optionsData($this->positionModel->select()); 120 | $form->textarea('description', '摘要')->maxlength(255); 121 | $form->text('link', '链接')->maxlength(255)->default('#'); 122 | $form->image('image', '图片')->mediumSize(); 123 | $form->number('sort', '排序')->default(0); 124 | $form->switchBtn('is_show', '显示')->default(1); 125 | if ($isEdit) { 126 | $form->show('create_time', '添加时间'); 127 | $form->show('update_time', '修改时间'); 128 | } 129 | } 130 | 131 | /** 132 | * 保存数据 133 | * 134 | * @param integer $id 135 | * @return void 136 | */ 137 | private function save($id = 0) 138 | { 139 | $data = request()->only([ 140 | 'title', 141 | 'position_id', 142 | 'description', 143 | 'link', 144 | 'image', 145 | 'sort', 146 | 'is_show', 147 | ], 'post'); 148 | 149 | $result = $this->validate($data, [ 150 | 'title|标题' => 'require', 151 | 'image|图片' => 'require', 152 | 'position_id|位置' => 'require', 153 | ]); 154 | 155 | if (true !== $result) { 156 | 157 | $this->error($result); 158 | } 159 | 160 | return $this->doSave($data, $id); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /app/admin/controller/Cmscategory.php: -------------------------------------------------------------------------------- 1 | dataModel = new Category; 29 | 30 | $this->pageTitle = '栏目管理'; 31 | $this->sortOrder = 'id desc'; 32 | $this->pagesize = 8; 33 | 34 | $this->selectSearch = 'name'; 35 | $this->selectFields = 'id,name'; 36 | $this->selectTextField = 'name'; 37 | } 38 | 39 | /** 40 | * 构建表单 41 | * 42 | * @param boolean $isEdit 43 | * @param array $data 44 | */ 45 | protected function buildForm($isEdit, &$data = []) 46 | { 47 | $form = $this->form; 48 | 49 | $tree = [0 => '根栏目']; 50 | 51 | $tree += $this->dataModel->getOptionsData($isEdit ? $data['id'] : 0); //数组合并不要用 array_merge , 会重排数组键 ,作为options导致bug 52 | 53 | $form->text('name', '名称')->required(); 54 | $form->select('parent_id', '上级')->required()->options($tree)->default(input('parend_id')); 55 | $form->text('link', '链接'); 56 | $form->image('logo', '封面图'); 57 | $form->switchBtn('is_show', '显示')->default(1); 58 | $form->radio('type', '类型')->default(1)->options([1 => '不限', 2 => '目录', 3 => '分类'])->required()->help('目录有下级,不能存文章。分类无下级,只能存文章'); 59 | $form->number('sort', '排序')->default(0)->required(); 60 | 61 | if ($isEdit) { 62 | $form->show('create_time', '添加时间'); 63 | $form->show('update_time', '修改时间'); 64 | } 65 | } 66 | 67 | /** 68 | * 构建表格 69 | * 70 | * @return void 71 | */ 72 | protected function buildTable(&$data = []) 73 | { 74 | $table = $this->table; 75 | $table->show('id', 'ID'); 76 | $table->raw('__text__', '结构')->getWrapper()->addStyle('text-align:left;'); 77 | $table->image('logo', '封面图')->thumbSize(50, 50); 78 | $table->show('link', '链接')->default('暂无'); 79 | $table->text('name', '名称')->autoPost('', true); 80 | $table->switchBtn('is_show', '显示')->default(1)->autoPost()->getWrapper()->addStyle('width:80px'); 81 | $table->match('type', '类型')->default(1)->options([1 => '不限', 2 => '目录', 3 => '分类'])->getWrapper()->addStyle('width:80px'); 82 | $table->text('sort', '排序')->autoPost('', true)->getWrapper()->addStyle('width:80px'); 83 | $table->show('content_count', '内容统计')->getWrapper()->addStyle('width:80px'); 84 | $table->show('create_time', '添加时间')->getWrapper()->addStyle('width:180px'); 85 | $table->show('update_time', '修改时间')->getWrapper()->addStyle('width:180px'); 86 | 87 | $table->sortable([]); 88 | 89 | $table->getActionbar() 90 | ->btnLink('add', url('add', ['parend_id' => '__data.pk__']), '', 'btn-secondary', 'mdi-plus', 'title="添加下级"') 91 | ->btnEdit() 92 | ->btnDelete() 93 | ->mapClass([ 94 | 'add' => [ 95 | 'hidden' => '__hi_add__' 96 | ] 97 | ]); 98 | 99 | foreach ($data as $d) { 100 | $d['__hi_add__'] = $d['type'] == 3; 101 | } 102 | } 103 | 104 | private function save($id = 0) 105 | { 106 | $data = request()->only([ 107 | 'name', 108 | 'parent_id', 109 | 'logo', 110 | 'link', 111 | 'is_show', 112 | 'type', 113 | 'sort', 114 | ], 'post'); 115 | 116 | $result = $this->validate($data, [ 117 | 'name|名称' => 'require', 118 | 'sort|排序' => 'require|number', 119 | 'type|类型' => 'require|number', 120 | 'parent_id|上级' => 'require|number', 121 | 'is_show' => 'require', 122 | ]); 123 | 124 | if (true !== $result) { 125 | 126 | $this->error($result); 127 | } 128 | 129 | if ($data['parent_id']) { 130 | $parent = $this->dataModel->find($data['parent_id']); 131 | if ($parent && $parent['type'] == 3) { 132 | $this->error($parent['name'] . '不允许有下级栏目,请重新选择'); 133 | } 134 | } 135 | 136 | if ($id && $data['parent_id'] == $id) { 137 | $this->error('上级不能是自己'); 138 | } 139 | 140 | return $this->doSave($data, $id); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /app/admin/controller/Cmsposition.php: -------------------------------------------------------------------------------- 1 | dataModel = new PositionModel; 30 | 31 | $this->pageTitle = '广告位置'; 32 | $this->sortOrder = 'id desc'; 33 | $this->pagesize = 8; 34 | 35 | $this->selectSearch = 'name'; 36 | $this->selectFields = 'id,name'; 37 | $this->selectTextField = 'name'; 38 | } 39 | 40 | /** 41 | * 构建表单 42 | * 43 | * @param boolean $isEdit 44 | * @param array $data 45 | */ 46 | protected function buildForm($isEdit, &$data = []) 47 | { 48 | $form = $this->form; 49 | 50 | $form->text('name', '名称')->required(); 51 | $form->image('logo', '封面图片'); 52 | $form->switchBtn('is_show', '显示')->default(1); 53 | $form->datetime('start_time', '开始时间')->required()->default(date('Y-m-d 00:00:00')); 54 | $form->datetime('end_time', '结束时间')->required()->default(date('Y-m-d 00:00:00', strtotime('+3year'))); 55 | $form->number('sort', '排序')->default(0)->required(); 56 | 57 | if ($isEdit) { 58 | $form->show('create_time', '添加时间'); 59 | $form->show('update_time', '修改时间'); 60 | } 61 | } 62 | 63 | protected function filterWhere() 64 | { 65 | $searchData = request()->get(); 66 | 67 | $where = []; 68 | if (!empty($searchData['name'])) { 69 | $where[] = ['name', 'like', '%' . $searchData['name'] . '%']; 70 | } 71 | 72 | return $where; 73 | } 74 | 75 | /** 76 | * 构建搜索 77 | * 78 | * @return void 79 | */ 80 | protected function buildSearch() 81 | { 82 | $search = $this->search; 83 | $search->text('name', '名称', 3)->maxlength(20); 84 | } 85 | 86 | /** 87 | * 构建表格 88 | * 89 | * @return void 90 | */ 91 | protected function buildTable(&$data = []) 92 | { 93 | $table = $this->table; 94 | $table->show('id', 'ID'); 95 | $table->image('logo', '封面')->thumbSize(50, 50); 96 | $table->text('name', '名称')->autoPost('', true); 97 | $table->switchBtn('is_show', '显示')->default(1)->autoPost()->getWrapper()->addStyle('width:120px'); 98 | $table->text('sort', '排序')->autoPost('', true)->getWrapper()->addStyle('width:100px'); 99 | $table->show('banner_count', '内容统计')->getWrapper()->addStyle('width:80px'); 100 | $table->show('start_time', '开始时间')->getWrapper()->addStyle('width:180px'); 101 | $table->show('end_time', '结束时间')->getWrapper()->addStyle('width:180px'); 102 | 103 | foreach ($data as &$d) { 104 | $d['__h_pv__'] = !$d['banner_count']; 105 | } 106 | 107 | unset($d); 108 | 109 | $table->sortable('id,sort'); 110 | 111 | $table->getActionbar() 112 | ->btnEdit() 113 | ->btnLink('preview', url('preview', ['id' => '__data.pk__']), '预览', 'btn-info', 'mdi mdi-eye-outline', 'title="预览" data-layer-size="580px,460px"') 114 | ->btnDelete() 115 | ->mapClass([ 116 | 'preview' => ['hidden' => '__h_pv__'], 117 | ]); 118 | } 119 | 120 | /** 121 | * Undocumented function 122 | * @title 预览 123 | * 124 | * @return mixed 125 | */ 126 | public function preview() 127 | { 128 | $id = input('id', 0); 129 | 130 | $list = CmsBanner::where('position_id', $id)->select(); 131 | 132 | $tpl = ''; 146 | 147 | $builder = $this->builder(''); 148 | $builder->content()->display($tpl, ['list' => $list]); 149 | return $builder; 150 | } 151 | 152 | private function save($id = 0) 153 | { 154 | $data = request()->only([ 155 | 'name', 156 | 'logo', 157 | 'is_show', 158 | 'start_time', 159 | 'end_time', 160 | 'sort', 161 | ], 'post'); 162 | 163 | $result = $this->validate($data, [ 164 | 'name|名称' => 'require', 165 | 'sort|排序' => 'require|number', 166 | 'start_time|开始时间' => 'require|date', 167 | 'end_time|结束时间' => 'require|date', 168 | 'is_show' => 'require', 169 | ]); 170 | 171 | if (true !== $result) { 172 | 173 | $this->error($result); 174 | } 175 | 176 | return $this->doSave($data, $id); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /app/admin/controller/Cmstag.php: -------------------------------------------------------------------------------- 1 | dataModel = new TagModel; 28 | 29 | $this->pageTitle = '内容标签'; 30 | $this->sortOrder = 'id desc'; 31 | $this->pagesize = 8; 32 | 33 | $this->selectSearch = 'name'; 34 | } 35 | 36 | /** 37 | * 构建表单 38 | * 39 | * @param boolean $isEdit 40 | * @param array $data 41 | */ 42 | protected function buildForm($isEdit, &$data = []) 43 | { 44 | $form = $this->form; 45 | 46 | $form->text('name', '名称')->required(); 47 | $form->image('logo', '封面图片'); 48 | $form->textarea('description', '描述')->maxlength(255); 49 | $form->text('link', '链接'); 50 | $form->switchBtn('is_show', '显示')->default(1); 51 | $form->number('sort', '排序')->default(0)->required(); 52 | 53 | if ($isEdit) { 54 | $form->show('create_time', '添加时间'); 55 | $form->show('update_time', '修改时间'); 56 | } 57 | } 58 | 59 | protected function filterWhere() 60 | { 61 | $searchData = request()->get(); 62 | 63 | $where = []; 64 | if (!empty($searchData['name'])) { 65 | $where[] = ['name', 'like', '%' . $searchData['name'] . '%']; 66 | } 67 | 68 | return $where; 69 | } 70 | 71 | /** 72 | * 构建搜索 73 | * 74 | * @return void 75 | */ 76 | protected function buildSearch() 77 | { 78 | $search = $this->search; 79 | $search->text('name', '名称', 3)->maxlength(20); 80 | } 81 | 82 | /** 83 | * 构建表格 84 | * 85 | * @return void 86 | */ 87 | protected function buildTable(&$data = []) 88 | { 89 | $table = $this->table; 90 | $table->show('id', 'ID'); 91 | $table->image('logo', '封面')->thumbSize(50, 50); 92 | $table->text('name', '名称')->autoPost('', true); 93 | $table->show('description', '描述')->getWrapper()->addStyle('width:30%;'); 94 | $table->switchBtn('is_show', '显示')->default(1)->autoPost()->getWrapper()->addStyle('width:120px'); 95 | $table->text('sort', '排序')->autoPost('', true)->getWrapper()->addStyle('width:120px'); 96 | 97 | $table->sortable('id,sort'); 98 | } 99 | 100 | private function save($id = 0) 101 | { 102 | $data = request()->only([ 103 | 'name', 104 | 'logo', 105 | 'description', 106 | 'link', 107 | 'is_show', 108 | 'sort', 109 | ], 'post'); 110 | 111 | $result = $this->validate($data, [ 112 | 'name|名称' => 'require', 113 | 'sort|排序' => 'require|number', 114 | 'is_show' => 'require', 115 | ]); 116 | 117 | if (true !== $result) { 118 | 119 | $this->error($result); 120 | } 121 | 122 | return $this->doSave($data, $id); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /app/admin/controller/Index.php: -------------------------------------------------------------------------------- 1 | currentAdmin = AdminUser::current(); 16 | } 17 | 18 | public function dashbord() 19 | { 20 | if ($this->currentAdmin['role_id'] == 1 || $this->currentAdmin['group_id'] == 1) { 21 | return $this->page1(); 22 | } else { 23 | return $this->page2(); 24 | } 25 | } 26 | 27 | private function page1() 28 | { 29 | $order_count = model\ShopOrder::count(); 30 | $goods_count = model\ShopGoods::count(); 31 | $member_count = model\Member::count(); 32 | $order_wait = model\ShopOrder::where(['pay_status' => 1, 'shipping_status' => 0])->count(); 33 | 34 | $days = []; 35 | $new_members = []; 36 | $recharges = []; 37 | 38 | for ($i = 6; $i >= 0; $i -= 1) { 39 | $day = date('Y-m-d', strtotime("-$i days")); 40 | $days[] = $day; 41 | $where = [ 42 | ['create_time', '>=', $day . ' 00:00:00'], 43 | ['create_time', '<=', $day . ' 23:59:59'], 44 | ]; 45 | 46 | $new_members[] = model\Member::where($where)->count(); 47 | $recharges[] = model\MemberRecharge::where($where)->where(['pay_status' => 1])->sum('account'); 48 | } 49 | $days = json_encode($days); 50 | $new_members = json_encode($new_members); 51 | $recharges = json_encode($recharges); 52 | 53 | $vars = compact('order_count', 'goods_count', 'member_count', 'order_wait', 'days', 'new_members', 'recharges'); 54 | 55 | return $this->fetch('', $vars); 56 | } 57 | 58 | private function page2() 59 | { 60 | return $this->fetch('dashbord2'); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/admin/controller/Memberlevel.php: -------------------------------------------------------------------------------- 1 | dataModel = new LevelModel; 27 | $this->pageTitle = '会员等级'; 28 | $this->sortOrder = 'level asc'; 29 | $this->selectSearch = 'name'; 30 | } 31 | 32 | protected function filterWhere() 33 | { 34 | $searchData = request()->get(); 35 | 36 | $where = []; 37 | 38 | if (!empty($searchData['name'])) { 39 | $where[] = ['name', 'like', '%' . $searchData['name'] . '%']; 40 | } 41 | 42 | return $where; 43 | } 44 | 45 | /** 46 | * 构建搜索 47 | * 48 | * @return void 49 | */ 50 | protected function buildSearch() 51 | { 52 | $search = $this->search; 53 | $search->text('name', '名称', 3)->maxlength(20); 54 | } 55 | 56 | /** 57 | * 构建表格 58 | * 59 | * @return void 60 | */ 61 | protected function buildTable(&$data = []) 62 | { 63 | $table = $this->table; 64 | 65 | $table->show('id', 'ID'); 66 | $table->text('name', '名称')->autoPost(); 67 | $table->text('level', '等级')->autoPost('', true)->getWrapper()->addStyle('width:150px'); 68 | $table->show('points', '积分条件'); 69 | $table->show('spend_money', '累计消费')->default(0); 70 | $table->show('member_count', '人数统计')->default(0); 71 | $table->show('description', '描述'); 72 | $table->show('create_time', '添加时间')->getWrapper()->addStyle('width:150px'); 73 | $table->show('update_time', '更新时间')->getWrapper()->addStyle('width:150px'); 74 | } 75 | 76 | /** 77 | * 构建表单 78 | * 79 | * @param boolean $isEdit 80 | * @param array $data 81 | */ 82 | protected function buildForm($isEdit, &$data = []) 83 | { 84 | $form = $this->form; 85 | 86 | $form->text('name', '名称'); 87 | $form->number('level', '等级'); 88 | $form->text('points', '积分条件')->size(2, 3); 89 | $form->text('spend_money', '累计消费')->size(2, 3); 90 | $form->textarea('description', '描述'); 91 | 92 | if ($isEdit) { 93 | $form->show('member_count', '人数统计'); 94 | $form->show('create_time', '添加时间'); 95 | $form->show('update_time', '更新时间'); 96 | } 97 | } 98 | 99 | /** 100 | * 保存数据 101 | * 102 | * @param integer $id 103 | * @return void 104 | */ 105 | private function save($id = 0) 106 | { 107 | $data = request()->only([ 108 | 'name', 109 | 'level', 110 | 'spend_money', 111 | 'points', 112 | 'description', 113 | ], 'post'); 114 | 115 | $result = $this->validate($data, [ 116 | 'name|名称' => 'require', 117 | 'level|等级' => 'require|number', 118 | 'spend_money|累计消费' => 'require|float', 119 | 'points|积分条件' => 'require|float', 120 | ]); 121 | 122 | if (true !== $result) { 123 | 124 | $this->error($result); 125 | } 126 | 127 | return $this->doSave($data, $id); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /app/admin/controller/Memberlog.php: -------------------------------------------------------------------------------- 1 | dataModel = new LogModel; 29 | $this->pageTitle = '会员日志'; 30 | 31 | $this->indexWith = ['member']; 32 | } 33 | 34 | protected function filterWhere() 35 | { 36 | $searchData = request()->get(); 37 | 38 | $where = []; 39 | if (!empty($searchData['member_id'])) { 40 | $where[] = ['member_id', '=', $searchData['member_id']]; 41 | } 42 | 43 | if (!empty($searchData['desc'])) { 44 | $where[] = ['desc', 'like', '%' . $searchData['desc'] . '%']; 45 | } 46 | 47 | if (!empty($searchData['type'])) { 48 | $where[] = [$searchData['type'], 'neq', 0]; 49 | } 50 | 51 | return $where; 52 | } 53 | 54 | /** 55 | * 构建搜索 56 | * 57 | * @return void 58 | */ 59 | protected function buildSearch() 60 | { 61 | $search = $this->search; 62 | 63 | $search->select('member_id', '会员', 3)->dataUrl(url('/admin/member/selectPage')); 64 | $search->text('desc', '描述', 3)->maxlength(20); 65 | } 66 | 67 | /** 68 | * 构建表格 69 | * 70 | * @return void 71 | */ 72 | protected function buildTable(&$data = []) 73 | { 74 | $table = $this->table; 75 | 76 | $table->show('id', 'ID'); 77 | $table->show('member.nickname', '会员'); 78 | $table->show('desc', '描述'); 79 | $table->show('change', '等级变动'); 80 | $table->show('create_time', '操作时间')->getWrapper()->addStyle('width:150px'); 81 | 82 | $table->getToolbar() 83 | ->btnRefresh(); 84 | 85 | $table->getActionbar() 86 | ->btnView(); 87 | 88 | $table->useCheckbox(false); 89 | } 90 | 91 | /** 92 | * 构建表单 93 | * 94 | * @param boolean $isEdit 95 | * @param array $data 96 | */ 97 | protected function buildForm($isEdit, &$data = []) 98 | { 99 | $form = $this->form; 100 | 101 | if ($isEdit == 2) { //查看 102 | 103 | $form->show('id', 'ID'); 104 | $form->show('nickname', '会员'); 105 | $form->show('desc', '描述'); 106 | $form->show('change', '等级变动'); 107 | $form->show('create_time', '操作时间'); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /app/admin/controller/Shippingcom.php: -------------------------------------------------------------------------------- 1 | dataModel = new ShippingComModel; 29 | 30 | $this->pageTitle = '快递公司'; 31 | $this->sortOrder = 'id ascs'; 32 | $this->pagesize = 14; 33 | 34 | $this->selectSearch = 'name|code'; 35 | $this->selectIdField = 'code'; 36 | } 37 | 38 | protected function filterWhere() 39 | { 40 | $searchData = request()->get(); 41 | 42 | $where = []; 43 | 44 | if (!empty($searchData['kwd'])) { 45 | $where[] = ['name|code', 'like', '%' . $searchData['kwd'] . '%']; 46 | } 47 | 48 | if (isset($searchData['enable']) && $searchData['enable'] != '') { 49 | $where[] = ['enable', '=', $searchData['enable']]; 50 | } 51 | 52 | return $where; 53 | } 54 | 55 | /** 56 | * 构建搜索 57 | * 58 | * @return void 59 | */ 60 | protected function buildSearch() 61 | { 62 | $search = $this->search; 63 | 64 | $search->text('kwd', '名称/编码', 3)->maxlength(55); 65 | $search->select('enable', '启用状态')->options([0 => '未启用', 1 => '已启用']); 66 | } 67 | 68 | /** 69 | * 构建表格 70 | * 71 | * @return void 72 | */ 73 | protected function buildTable(&$data = []) 74 | { 75 | $table = $this->table; 76 | 77 | $table->show('id', 'ID'); 78 | $table->show('name', '公司名称'); 79 | $table->show('code', '编码'); 80 | $table->switchBtn('enable', '启用')->autoPost(); 81 | 82 | $table->getToolbar() 83 | ->btnRefresh(); 84 | 85 | $table->sortable('name'); 86 | $table->useActionbar(false); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/admin/controller/Shopbrand.php: -------------------------------------------------------------------------------- 1 | dataModel = new Brand; 29 | 30 | $this->pageTitle = '产品品牌'; 31 | $this->sortOrder = 'id desc'; 32 | $this->pagesize = 8; 33 | 34 | $this->selectSearch = 'name'; 35 | $this->selectFields = 'id,name'; 36 | $this->selectTextField = 'name'; 37 | } 38 | 39 | /** 40 | * 构建表单 41 | * 42 | * @param boolean $isEdit 43 | * @param array $data 44 | */ 45 | protected function buildForm($isEdit, &$data = []) 46 | { 47 | $form = $this->form; 48 | 49 | $tree = [0 => '根品牌']; 50 | 51 | $tree += $this->dataModel->getOptionsData($isEdit ? $data['id'] : 0); //数组合并不要用 array_merge , 会重排数组键 ,作为options导致bug 52 | 53 | $form->text('name', '名称')->required(); 54 | $form->select('parent_id', '上级')->required()->options($tree)->default(input('parend_id')); 55 | $form->text('link', '链接'); 56 | $form->image('logo', '封面图片'); 57 | $form->switchBtn('is_show', '显示')->default(1); 58 | $form->radio('type', '类型')->default(1)->options([1 => '不限', 2 => '目录', 3 => '品牌'])->required()->help('目录有下级,不能存产品。品牌无下级,只能存产品'); 59 | $form->text('sort', '排序')->default(0)->required(); 60 | 61 | if ($isEdit) { 62 | $form->show('create_time', '添加时间'); 63 | $form->show('update_time', '修改时间'); 64 | } 65 | } 66 | 67 | /** 68 | * 构建表格 69 | * 70 | * @return void 71 | */ 72 | protected function buildTable(&$data = []) 73 | { 74 | $table = $this->table; 75 | $table->show('id', 'ID'); 76 | $table->raw('__text__', '结构')->getWrapper()->addStyle('text-align:left;'); 77 | $table->image('logo', '封面')->thumbSize(50, 50); 78 | $table->show('link', '链接')->default('暂无'); 79 | $table->text('name', '名称')->autoPost('', true)->getWrapper()->addStyle('max-width:80px'); 80 | $table->switchBtn('is_show', '显示')->default(1)->autoPost()->getWrapper()->addStyle('width:80px'); 81 | $table->text('sort', '排序')->autoPost('', true)->getWrapper()->addStyle('width:80px'); 82 | $table->show('goods_count', '产品统计')->getWrapper()->addStyle('width:80px'); 83 | $table->raw('times', '添加/修改时间')->getWrapper()->addStyle('width:180px'); 84 | 85 | foreach ($data as &$d) { 86 | $d['times'] = $d['create_time'] . '
' . $d['update_time']; 87 | } 88 | 89 | unset($d); 90 | 91 | $table->sortable([]); 92 | 93 | $table->getActionbar() 94 | ->btnLink('add', url('add', ['parend_id' => '__data.pk__']), '', 'btn-secondary', 'mdi-plus', 'title="添加下级"') 95 | ->btnEdit() 96 | ->btnDelete(); 97 | } 98 | 99 | private function save($id = 0) 100 | { 101 | $data = request()->only([ 102 | 'name', 103 | 'parent_id', 104 | 'logo', 105 | 'link', 106 | 'is_show', 107 | 'type', 108 | 'sort', 109 | 'model', 110 | 'attr', 111 | ], 'post'); 112 | 113 | $result = $this->validate($data, [ 114 | 'name|名称' => 'require', 115 | 'sort|排序' => 'require|number', 116 | 'type|类型' => 'require|number', 117 | 'parent_id|上级' => 'require|number', 118 | 'is_show' => 'require', 119 | ]); 120 | 121 | if (true !== $result) { 122 | 123 | $this->error($result); 124 | } 125 | 126 | if ($data['parent_id']) { 127 | $parent = $this->dataModel->find($data['parent_id']); 128 | if ($parent && $parent['type'] == 3) { 129 | $this->error('[' . $parent['name'] . ']不允许有下级品牌,请重新选择'); 130 | } 131 | } 132 | 133 | if ($id && $data['parent_id'] == $id) { 134 | $this->error('上级不能是自己'); 135 | } 136 | 137 | return $this->doSave($data, $id); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /app/admin/controller/Shopcategory.php: -------------------------------------------------------------------------------- 1 | dataModel = new Category; 29 | 30 | $this->pageTitle = '产品分类'; 31 | $this->sortOrder = 'id desc'; 32 | $this->pagesize = 8; 33 | 34 | $this->selectSearch = 'name'; 35 | $this->selectFields = 'id,name'; 36 | $this->selectTextField = 'name'; 37 | } 38 | 39 | /** 40 | * 构建表单 41 | * 42 | * @param boolean $isEdit 43 | * @param array $data 44 | */ 45 | protected function buildForm($isEdit, &$data = []) 46 | { 47 | $form = $this->form; 48 | 49 | $tree = [0 => '根分类']; 50 | 51 | $tree += $this->dataModel->getOptionsData($isEdit ? $data['id'] : 0); //数组合并不要用 array_merge , 会重排数组键 ,作为options导致bug 52 | 53 | $form->text('name', '名称')->required(); 54 | $form->select('parent_id', '上级')->required()->options($tree)->default(input('parend_id')); 55 | $form->text('link', '链接'); 56 | $form->image('logo', '封面图片'); 57 | $form->switchBtn('is_show', '显示')->default(1); 58 | $form->radio('type', '类型')->default(1)->options([1 => '不限', 2 => '目录', 3 => '分类'])->required()->help('目录有下级,不能存产品。分类无下级,只能存产品'); 59 | $form->text('sort', '排序')->default(0)->required(); 60 | 61 | if ($isEdit) { 62 | $form->show('create_time', '添加时间'); 63 | $form->show('update_time', '修改时间'); 64 | } 65 | } 66 | 67 | /** 68 | * 构建表格 69 | * 70 | * @return void 71 | */ 72 | protected function buildTable(&$data = []) 73 | { 74 | $table = $this->table; 75 | $table->show('id', 'ID'); 76 | $table->raw('__text__', '结构')->getWrapper()->addStyle('text-align:left;'); 77 | $table->image('logo', '封面')->thumbSize(50, 50); 78 | $table->show('link', '链接')->default('暂无'); 79 | $table->text('name', '名称')->autoPost('', true)->getWrapper()->addStyle('max-width:80px'); 80 | $table->switchBtn('is_show', '显示')->default(1)->autoPost()->getWrapper()->addStyle('width:80px'); 81 | $table->text('sort', '排序')->autoPost('', true)->getWrapper()->addStyle('width:80px'); 82 | $table->show('goods_count', '产品统计')->getWrapper()->addStyle('width:80px'); 83 | $table->raw('times', '添加/修改时间')->getWrapper()->addStyle('width:180px'); 84 | 85 | foreach ($data as &$d) { 86 | $d['times'] = $d['create_time'] . '
' . $d['update_time']; 87 | } 88 | 89 | unset($d); 90 | 91 | $table->sortable([]); 92 | 93 | $table->getActionbar() 94 | ->btnLink('add', url('add', ['parend_id' => '__data.pk__']), '', 'btn-secondary', 'mdi-plus', 'title="添加下级"') 95 | ->btnEdit() 96 | ->btnDelete() 97 | ->mapClass([ 98 | 'add' => [ 99 | 'hidden' => '__hi_add__' 100 | ] 101 | ]); 102 | 103 | foreach ($data as $d) { 104 | $d['__hi_add__'] = $d['type'] == 3; 105 | } 106 | } 107 | 108 | private function save($id = 0) 109 | { 110 | $data = request()->only([ 111 | 'name', 112 | 'parent_id', 113 | 'logo', 114 | 'link', 115 | 'is_show', 116 | 'type', 117 | 'sort', 118 | 'model', 119 | 'attr', 120 | ], 'post'); 121 | 122 | $result = $this->validate($data, [ 123 | 'name|名称' => 'require', 124 | 'sort|排序' => 'require|number', 125 | 'type|类型' => 'require|number', 126 | 'parent_id|上级' => 'require|number', 127 | 'is_show' => 'require', 128 | ]); 129 | 130 | if (true !== $result) { 131 | 132 | $this->error($result); 133 | } 134 | 135 | if ($data['parent_id']) { 136 | $parent = $this->dataModel->find($data['parent_id']); 137 | if ($parent && $parent['type'] == 3) { 138 | $this->error('[' . $parent['name'] . ']不允许有下级分类,请重新选择'); 139 | } 140 | } 141 | 142 | if ($id && $data['parent_id'] == $id) { 143 | $this->error('上级不能是自己'); 144 | } 145 | 146 | return $this->doSave($data, $id); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /app/admin/controller/Shopcoupontype.php: -------------------------------------------------------------------------------- 1 | dataModel = new CouponTypeModel; 30 | 31 | $this->pageTitle = '优惠券类型'; 32 | $this->sortOrder = 'id desc'; 33 | $this->pagesize = 14; 34 | 35 | $this->selectSearch = 'name'; 36 | } 37 | 38 | /** 39 | * 构建表单 40 | * 41 | * @param boolean $isEdit 42 | * @param array $data 43 | */ 44 | protected function buildForm($isEdit, &$data = []) 45 | { 46 | $form = $this->form; 47 | 48 | $form->text('name', '名称')->autoPost('', true)->required(); 49 | $form->radio('card_type', '类型')->options([1 => '折扣券', 2 => '购物券'])->readonly($isEdit) 50 | ->required()->help('折扣券:给产品打折;
购物券:购买一个面额以内产品任意,若是指定产品的,则不限面额'); 51 | $form->radio('type', '发放方式')->options([0 => '面额模板', 1 => '按用户发放', 2 => '注册', 3 => '邀请', 4 => '线下发放'])->required(); 52 | $form->text('money', '面额')->required()->default(0)->help('折扣(折扣券)或金额(购物券)'); 53 | //$form->text('condition ', '使用条件'); 54 | $form->number('create_num ', '累计发放数量')->default(1000)->required(); 55 | $form->date('send_start_time ', '发放开始时间')->default(date('Y-m-d')); 56 | $form->date('send_end_time ', '发放结束时间')->default(date('Y-m-d', strtotime('+9year'))); 57 | $form->date('use_start_time ', '使用开始时间')->default(date('Y-m-d')); 58 | $form->date('use_end_time ', '使用结束时间')->default(date('Y-m-d', strtotime('+9year'))); 59 | $form->radio('status ', '状态')->options([0 => '禁用', 1 => '正常'])->default(1); 60 | $form->multipleSelect('for_goods ', '指定商品使用')->dataUrl(url('/admin/shopgoods/selectPage')); 61 | 62 | if ($isEdit) { 63 | 64 | $form->show('send_num ', '已发放数量'); 65 | $form->show('use_num ', '已使用数量'); 66 | $form->show('get_num ', '已领取数量'); 67 | $form->show('del_num ', '已删除'); 68 | 69 | $form->show('create_time', '添加时间'); 70 | $form->show('update_time', '修改时间'); 71 | } 72 | } 73 | 74 | protected function filterWhere() 75 | { 76 | $searchData = request()->get(); 77 | 78 | $where = []; 79 | 80 | if (!empty($searchData['name'])) { 81 | $where[] = ['name', 'like', '%' . $searchData['card_type'] . '%']; 82 | } 83 | 84 | if (!empty($searchData['card_type'])) { 85 | $where[] = ['card_type', '=', $searchData['card_type']]; 86 | } 87 | 88 | return $where; 89 | } 90 | 91 | /** 92 | * 构建搜索 93 | * 94 | * @return void 95 | */ 96 | protected function buildSearch() 97 | { 98 | $search = $this->search; 99 | $search->text('name', '名称', 3)->maxlength(20); 100 | $search->select('card_type', '名称', 3)->options([1 => '折扣券', 2 => '购物券']); 101 | } 102 | 103 | /** 104 | * 构建表格 105 | * 106 | * @return void 107 | */ 108 | protected function buildTable(&$data = []) 109 | { 110 | $table = $this->table; 111 | $table->show('id', 'ID'); 112 | $table->text('name', '名称')->autoPost('', true)->getWrapper()->addStyle('max-width:120px;'); 113 | $table->match('card_type', '类型')->options([1 => '折扣券', 2 => '购物券']); 114 | $table->match('type', '发放方式')->options([0 => '面额模板', 1 => '按用户发放', 2 => '注册', 3 => '邀请', 4 => '线下发放']); 115 | $table->show('money', '面额'); 116 | $table->show('condition ', '使用条件'); 117 | $table->fields('nums1', '预计/已发')->with( 118 | $table->show('create_num ', '累计发放数量'), 119 | $table->show('send_num ', '已发放数量') 120 | )->getWrapper()->addStyle('width:100px;'); 121 | $table->fields('nums2', '使用/领取数量')->with( 122 | $table->show('use_num ', '已使用数量'), 123 | $table->show('get_num ', '已领取数量') 124 | )->getWrapper()->addStyle('width:100px;'); 125 | $table->show('del_num ', '已删除数量'); 126 | $table->fields('send_times', '发放开始/结束时间')->with( 127 | $table->show('send_start_time ', '发放开始时间'), 128 | $table->show('send_end_time ', '发放结束时间') 129 | )->getWrapper()->addStyle('width:100px;'); 130 | 131 | $table->fields('use_times', '使用开始/结束时间')->with( 132 | $table->show('use_start_time ', '使用开始时间'), 133 | $table->show('use_end_time ', '使用结束时间') 134 | )->getWrapper()->addStyle('width:100px;'); 135 | 136 | $table->show('create_time ', '添加时间')->getWrapper()->addStyle('width:160px;'); 137 | $table->switchBtn('status ', '状态')->autoPost(); 138 | $table->matches('for_goods ', '指定商品使用')->optionsData(ShopGoods::select(), 'name')->getWrapper()->addStyle('max-width:200px;');; 139 | $table->sortable('id,money,send_num,use_num,get_num'); 140 | 141 | $table->getActionbar() 142 | ->btnEdit() 143 | ->btnDelete(); 144 | } 145 | 146 | private function save($id = 0) 147 | { 148 | $data = request()->post(); 149 | 150 | $result = $this->validate($data, [ 151 | 'name|名称' => 'require', 152 | 'card_type|类型' => 'require|number', 153 | 'type|发放方式' => 'require|number', 154 | 'money|面额' => 'require|float|gt:0', 155 | 'create_num|累计发放数量' => 'require|number|gt:0', 156 | ]); 157 | 158 | if (true !== $result) { 159 | $this->error($result); 160 | } 161 | 162 | if ($data['card_type'] == 1 && ($data['money'] <= 0 || $data['money'] >= 10)) { 163 | $this->error('折扣应该在0折~10折之间'); 164 | } 165 | 166 | if (!isset($data['for_goods'])) { //多选,如果没有选择任何值,参数里面将不存在这个键 167 | $data['for_goods'] = ''; 168 | } 169 | 170 | return $this->doSave($data, $id); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /app/admin/controller/Shoptag.php: -------------------------------------------------------------------------------- 1 | dataModel = new TagModel; 29 | 30 | $this->pageTitle = '产品标签'; 31 | $this->sortOrder = 'id desc'; 32 | $this->pagesize = 8; 33 | 34 | $this->selectSearch = 'name'; 35 | } 36 | 37 | /** 38 | * 构建表单 39 | * 40 | * @param boolean $isEdit 41 | * @param array $data 42 | */ 43 | protected function buildForm($isEdit, &$data = []) 44 | { 45 | $form = $this->form; 46 | 47 | $form->text('name', '名称')->required(); 48 | $form->image('logo', '封面图片'); 49 | $form->textarea('description', '描述')->maxlength(255); 50 | $form->text('link', '链接'); 51 | $form->switchBtn('is_show', '显示')->default(1); 52 | $form->number('sort', '排序')->default(0)->required(); 53 | 54 | if ($isEdit) { 55 | $form->show('create_time', '添加时间'); 56 | $form->show('update_time', '修改时间'); 57 | } 58 | } 59 | 60 | protected function filterWhere() 61 | { 62 | $searchData = request()->get(); 63 | 64 | $where = []; 65 | if (!empty($searchData['name'])) { 66 | $where[] = ['name', 'like', '%' . $searchData['name'] . '%']; 67 | } 68 | 69 | return $where; 70 | } 71 | 72 | /** 73 | * 构建搜索 74 | * 75 | * @return void 76 | */ 77 | protected function buildSearch() 78 | { 79 | $search = $this->search; 80 | $search->text('name', '名称', 3)->maxlength(20); 81 | } 82 | 83 | /** 84 | * 构建表格 85 | * 86 | * @return void 87 | */ 88 | protected function buildTable(&$data = []) 89 | { 90 | $table = $this->table; 91 | $table->show('id', 'ID'); 92 | $table->image('logo', '封面')->thumbSize(50, 50); 93 | $table->text('name', '名称')->autoPost('', true); 94 | $table->show('description', '描述')->getWrapper()->addStyle('width:30%;'); 95 | $table->switchBtn('is_show', '显示')->default(1)->autoPost()->getWrapper()->addStyle('width:120px'); 96 | $table->text('sort', '排序')->autoPost('', true)->getWrapper()->addStyle('width:120px'); 97 | 98 | $table->sortable('id,sort'); 99 | } 100 | 101 | private function save($id = 0) 102 | { 103 | $data = request()->only([ 104 | 'name', 105 | 'logo', 106 | 'description', 107 | 'link', 108 | 'is_show', 109 | 'sort', 110 | ], 'post'); 111 | 112 | $result = $this->validate($data, [ 113 | 'name|名称' => 'require', 114 | 'sort|排序' => 'require|number', 115 | 'is_show' => 'require', 116 | ]); 117 | 118 | if (true !== $result) { 119 | 120 | $this->error($result); 121 | } 122 | 123 | return $this->doSave($data, $id); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /app/admin/view/index/dashbord.html: -------------------------------------------------------------------------------- 1 | {extend name="$admin_layout"/} 2 | 3 | {block name="style"} 4 | 16 | {/block} 17 | 18 | {block name="content"} 19 |
20 |
21 |
22 |
23 |
24 |

订单总数

25 |

{$order_count}

27 |
28 |
30 |
31 |
32 |
33 | 34 |
35 |
36 |
37 |
38 |

产品总数

39 |

{$goods_count}

41 |
42 |
44 |
45 |
46 |
47 | 48 |
49 |
50 |
51 |
52 |

会员总数

53 |

{$member_count}

55 |
56 |
58 |
59 |
60 |
61 | 62 |
63 |
64 |
65 |
66 |

待处理订单

67 |

{$order_wait}

69 |
70 |
72 |
73 |
74 |
75 |
76 | 77 |
78 | 79 |
80 |
81 |
82 |

近7天用户注册数

83 |
84 |
85 | 86 |
87 |
88 |
89 | 90 |
91 |
92 |
93 |

近7天充值金额

94 |
95 |
96 | 97 |
98 |
99 |
100 | 101 |
102 | 103 | 104 | {notempty name="$admin_copyright"} 105 | 108 | {/notempty} 109 | {/block} 110 | 111 | {block name="script"} 112 | 113 | 114 | 160 | {/block} -------------------------------------------------------------------------------- /app/admin/view/index/dashbord2.html: -------------------------------------------------------------------------------- 1 | {extend name="$admin_layout"/} 2 | 3 | {block name="style"} 4 | 16 | {/block} 17 | 18 | {block name="content"} 19 | 20 | {/block} -------------------------------------------------------------------------------- /app/admin/view/member/tree.html: -------------------------------------------------------------------------------- 1 | {extend name="$admin_layout"/} 2 | 3 | {block name="style"} 4 | 42 | 43 | {/block} 44 | 45 | {block name="content"} 46 |
47 |
48 |
49 |
50 | 75 |
76 |
77 |
78 |
    79 | {volist name="members" id="v"} 80 |
  • 81 | 82 | 83 | {$v.id}: {$v.nickname}({$v.lowers}) 84 | 85 |
  • 86 | {/volist} 87 |
88 |
89 |
90 |
91 |
92 |
93 | {/block} 94 | 95 | {block name="script"} 96 | 125 | {/block} 126 | -------------------------------------------------------------------------------- /app/common/logic/AccountLogic.php: -------------------------------------------------------------------------------- 1 | errors = []; 21 | $data = array_merge([ 22 | 'member_id' => $member_id, 23 | 'points' => 0, 24 | 'money' => 0, 25 | 'commission' => 0, 26 | 'remark' => '', 27 | 'admin_id' => session('admin_id') ?: 0, 28 | 'order_id' => 0, 29 | 'tag' => '', 30 | ], $data); 31 | 32 | if ($data['points'] == 0 && $data['money'] == 0 && $data['commission'] == 0) { 33 | return ['code' => 0, 'msg' => model\MemberAccount::getNames() . '不能全部为 0']; 34 | } 35 | 36 | Db::startTrans(); 37 | 38 | $sql = ''; 39 | try 40 | { 41 | $prefix = config('thinkorm.connections.mysql.prefix', ''); 42 | 43 | $sql = "UPDATE {$prefix}member SET points = points + {$data['points']}," . 44 | " money = money + {$data['money']}, commission = commission + {$data['commission']}" 45 | . " WHERE id = $member_id"; 46 | 47 | $res0 = Db::execute($sql); 48 | 49 | $memberAccountModel = new model\MemberAccount(); 50 | $res1 = $memberAccountModel->save($data); 51 | 52 | if ($res0 && $res1) { 53 | Db::commit(); 54 | 55 | return ['code' => 1, 'msg' => 'ok']; 56 | } else { 57 | Log::alert('执行sql失败:' . $sql); 58 | Db::rollback(); 59 | 60 | return ['code' => 0, 'msg' => '未知错误-sql有误或无更改']; 61 | } 62 | } catch (\Exception $e) { 63 | Db::rollback(); 64 | 65 | $msg = $e->getMessage(); 66 | 67 | $types = model\MemberAccount::$types; 68 | 69 | if (preg_match('/.+?Out\s+of\s+range\s+value\s+for\s+column\s+[\'\"`](\w+)[\'\"`]/im', $msg, $matchs)) { 70 | $msg = (isset($types[$matchs[1]]) ? $types[$matchs[1]] : $matchs[1]) . '不足'; 71 | } 72 | 73 | Log::alert('执行sql出错:' . $sql); 74 | Log::error($e->getMessage()); 75 | 76 | return ['code' => 0, 'msg' => $msg]; 77 | } 78 | } 79 | 80 | /** 81 | * Undocumented function 82 | * 83 | * @param int $member_id 84 | * @param int|float $points 85 | * @return array 86 | */ 87 | public function editMemberPoints($member_id, $points, $remark = '', $tag = '') 88 | { 89 | $data = [ 90 | 'points' => $points, 91 | 'remark' => $remark, 92 | 'tag' => $tag, 93 | ]; 94 | 95 | return $this->editMemberAccount($member_id, $data); 96 | } 97 | 98 | /** 99 | * Undocumented function 100 | * 101 | * @param int $member_id 102 | * @param int|float $money 103 | * @return array 104 | */ 105 | public function editMemberMoney($member_id, $money, $remark = '', $tag = '') 106 | { 107 | $data = [ 108 | 'money' => $money, 109 | 'remark' => $remark, 110 | 'tag' => $tag, 111 | ]; 112 | 113 | return $this->editMemberAccount($member_id, $data); 114 | } 115 | 116 | /** 117 | * Undocumented function 118 | * 119 | * @param int $member_id 120 | * @param int|float $commission 121 | * @return array 122 | */ 123 | public function editMemberCommission($member_id, $commission, $remark = '', $tag = '') 124 | { 125 | $data = [ 126 | 'commission' => $commission, 127 | 'remark' => $remark, 128 | 'tag' => $tag, 129 | ]; 130 | 131 | return $this->editMemberAccount($member_id, $data); 132 | } 133 | 134 | public function hasEnouth($member_id, $type, $num) 135 | { 136 | $memberModel = new model\Member(); 137 | 138 | $member = $memberModel->find($member_id); 139 | if (!$member) { 140 | return ['code' => 0, 'msg' => '会员不存在' . $member_id, 'current' => 0]; 141 | } 142 | if ($num <= 0) { 143 | return ['code' => 0, 'msg' => '输入值不能小于等于0', 'current' => 0]; 144 | } 145 | 146 | if (!isset($member[$type])) { 147 | return ['code' => 0, 'msg' => '参数错误-' . $type, 'current' => 0]; 148 | } 149 | 150 | if ($member[$type] < $num) { 151 | return ['code' => 0, 'msg' => model\MemberAccount::$types[$type] . '不足,最多可用' . $member[$type], 'current' => $member[$type]]; 152 | } 153 | 154 | return ['code' => 1, 'msg' => 'ok', 'current' => $member[$type]]; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /app/common/logic/CouponLogic.php: -------------------------------------------------------------------------------- 1 | 0, 'msg' => '参数有误']; 14 | } 15 | 16 | $couponType = model\ShopCouponType::find($coupon_type_id); 17 | 18 | if (!$couponType) { 19 | return ['code' => 0, 'msg' => '优惠券类型不存在']; 20 | } 21 | 22 | $list = []; 23 | for ($i = 1; $i <= $num; $i += 1) { 24 | $data = [ 25 | 'member_id' => $member_id, 26 | 'coupon_type_id' => $coupon_type_id, 27 | 'no_' => '0', //非线下,无卡号 28 | 'code' => $member_id . '_' . $i . $this->get_rand_str(8, 0, 1), //赠送的,就不需要严格不重复了,随便生成一个 29 | 'create_time' => date('Y-m-d H:i:s'), 30 | 'order_id' => 0, 31 | 'get_time' => date('Y-m-d H:i:s'), 32 | 'status' => 1, 33 | 'card_type' => $couponType['card_type'], 34 | ]; 35 | $list[] = $data; 36 | } 37 | 38 | $coupon = new model\ShopCouponList; 39 | 40 | $res = $coupon->saveAll($list); 41 | 42 | $c = count($res); 43 | 44 | if ($c > 0) { 45 | model\MemberLog::create([ 46 | 'member_id' => $member_id, 47 | 'desc' => "获得优惠券:{$couponType['name']}{$c}张.", 48 | 'change' => '', 49 | 'create_time' => date('Y-m-d H:i:s'), 50 | ]); 51 | 52 | model\ShopCouponType::where(['id' => $coupon_type_id])->setInc('send_num', $c); 53 | model\ShopCouponType::where(['id' => $coupon_type_id])->setInc('get_num', $c); 54 | 55 | $prefix = config('database.prefix'); 56 | 57 | $sql = "UPDATE {$prefix}shop_coupon_list SET `no_` = 10000 + `id` where `no_` = 0"; 58 | 59 | Db::execute($sql); 60 | 61 | return ['code' => 1, 'msg' => '发送成功提货券' . $c . '张']; 62 | } 63 | 64 | return ['code' => 0, 'msg' => '发送提货券失败']; 65 | } 66 | 67 | public function get_rand_str($randLength = 6, $addtime = 1, $includenumber = 0) 68 | { 69 | if ($includenumber) { 70 | $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQEST123456789'; 71 | } else { 72 | $chars = 'abcdefghijklmnopqrstuvwxyz'; 73 | } 74 | $len = strlen($chars); 75 | $randStr = ''; 76 | for ($i = 0; $i < $randLength; $i++) { 77 | $randStr .= $chars[rand(0, $len - 1)]; 78 | } 79 | $tokenvalue = $randStr; 80 | if ($addtime) { 81 | $tokenvalue = $randStr . time(); 82 | } 83 | return $tokenvalue; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/common/logic/PaymentLogic.php: -------------------------------------------------------------------------------- 1 | msg; 21 | } 22 | 23 | public function debug($val = true) 24 | { 25 | $this->debug = $val; 26 | } 27 | 28 | /** 29 | * Undocumented function 30 | * 31 | * @param string $order_sn 格式 order_23_1593307455/recharge_34_1593307345 32 | * @param array $extData 33 | * @return boolean 34 | */ 35 | public function paySuccess($order_sn, $extData = []) 36 | { 37 | if (!empty($order_sn)) { 38 | return false; 39 | } 40 | 41 | $arr = explode('_', $order_sn); 42 | 43 | if (count($arr) > 2) { 44 | $type = $arr[0]; 45 | $id = intval($arr[1]); 46 | if ($type == 'order') { 47 | return $this->orderPaySuccess($id, $extData); 48 | } else if ($type == 'recharge') { 49 | return $this->rechargePaySuccess($id, $extData); 50 | } 51 | } 52 | 53 | return false; 54 | } 55 | 56 | /** 57 | * Undocumented function 58 | * 59 | * @param int $order_id 60 | * @param array $extData 61 | * @return boolean 62 | */ 63 | public function orderPaySuccess($order_id, $extData) 64 | { 65 | if (empty($order_id)) { 66 | return false; 67 | } 68 | 69 | $orderModel = new model\ShopOrder(); 70 | 71 | $order = $orderModel->where(['id' => $order_id, 'pay_status' => 0])->find(); 72 | 73 | if (!$order) { 74 | return true; 75 | } 76 | 77 | $data = ['pay_status' => 1, 'pay_time' => date('Y-m-d H:i:s')]; 78 | 79 | if (!empty($extData) && isset($extData['transaction_id'])) //data里面有微信交易id,写入订单里面,以支持后续退款操作 80 | { 81 | $data['transaction_id'] = $extData['transaction_id']; 82 | } 83 | 84 | if (!empty($extData) && isset($extData['pay_code'])) { 85 | $data['pay_code'] = $extData['pay_code']; 86 | } 87 | 88 | $order->save($data); //先保存一次,防止支付接口重复通知 89 | 90 | $orderLogic = new OrderLogic($order['member_id']); 91 | 92 | $orderLogic->logOrder($order_id, '订单付款成功', '付款成功', $order['member_id']); 93 | 94 | $orderData = []; 95 | 96 | if ($order['order_status'] == 0) { //待确认 97 | $orderData['order_status'] = 1; 98 | } 99 | 100 | $order->save($orderData); 101 | 102 | $cartLogic = new CartLogic($order['member_id']); 103 | 104 | $cartLogic->minusStock($order_id); 105 | 106 | $member = model\Member::find($order['member_id']); 107 | 108 | if (!$member) { 109 | // 110 | } else { 111 | $this->goodsProfit($member, $order); //推荐奖励 112 | } 113 | 114 | return true; 115 | } 116 | 117 | /** 118 | * Undocumented function 119 | * 120 | * @param int $recharge_id 121 | * @param array $extData 122 | * @return boolean 123 | */ 124 | public function rechargePaySuccess($recharge_id, $extData) 125 | { 126 | if (empty($recharge_id)) { 127 | return false; 128 | } 129 | 130 | $rechargeModel = new model\MemberRecharge(); 131 | 132 | $recharge = $rechargeModel->where(['id' => $recharge_id, 'pay_status' => 0])->find(); 133 | 134 | if (!$recharge) { 135 | return true; 136 | } 137 | 138 | $data = ['pay_status' => 1, 'pay_time' => date('Y-m-d H:i:s')]; 139 | 140 | if (!empty($extData) && isset($extData['transaction_id'])) //data里面有微信交易id,写入订单里面,以支持后续退款操作 141 | { 142 | $data['transaction_id'] = $extData['transaction_id']; 143 | } 144 | 145 | if (!empty($extData) && isset($extData['pay_code'])) { 146 | $data['pay_code'] = $extData['pay_code']; 147 | } 148 | 149 | $recharge->save($data); //先保存一次,防止支付接口重复通知 150 | 151 | $account = new AccountLogic; 152 | 153 | if (isset(model\MemberRecharge::$get_goods_methds[$recharge['goods_method']])) { 154 | 155 | $money = model\MemberRecharge::$mnoeys[$recharge['goods_method']]; 156 | 157 | if ($money['coupon'] > 0) { 158 | $couponLogic = new CouponLogic; 159 | $res_cp = $couponLogic->create($recharge['member_id'], 1, $money['coupon']); 160 | } 161 | 162 | if ($money['points'] > 0) { 163 | $res = $account->editMemberPoints($recharge['member_id'], $money['points'], '充值获得', 'recharge'); 164 | } 165 | } else { 166 | // 167 | } 168 | 169 | $recharge['goods_price'] = $recharge['account']; 170 | 171 | $member = model\Member::find($recharge['member_id']); 172 | if (!$member) { 173 | // 174 | } else { 175 | $this->shareProfit($member, $recharge); //分享奖励 176 | $this->agentLevelUp($member, $recharge); //代理升级 177 | } 178 | 179 | return true; 180 | } 181 | 182 | /** 183 | * Undocumented function 184 | * 185 | * @param array $recharge 186 | * @return boolean 187 | */ 188 | public function agentLevelUp($member, $recharge) 189 | { 190 | if ($member['agent_level'] < 1) { 191 | if (!$this->debug) { 192 | $memberLogic = new MemberLogic; 193 | $res_lv = $memberLogic->changeAgentLevel($recharge['member_id'], 1, '充值成功,代理等级提升'); 194 | if ($res_lv['code'] != 1) { 195 | return false; 196 | } else { 197 | return true; 198 | } 199 | } else { 200 | 201 | } 202 | } else { 203 | 204 | } 205 | 206 | return true; 207 | } 208 | 209 | public function shareProfit($member, $recharge) 210 | { 211 | 212 | } 213 | 214 | public function goodsProfit($member, $order) 215 | { 216 | 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /app/common/logic/RechargeLogic.php: -------------------------------------------------------------------------------- 1 | 'require', 15 | 'goods_method|方式' => 'require|float|egt:0', 16 | ]); 17 | 18 | if (true !== $v->check($data)) { 19 | return ['code' => 0, 'msg' => '参数有误-' . $v->getError()]; 20 | } 21 | 22 | $config_key = 'commission'; 23 | 24 | $member = model\Member::find($member_id); 25 | if (!$member) { 26 | return ['code' => 0, 'msg' => '会员不存在:' . $member_id]; 27 | } 28 | 29 | if ($member['agent_level'] < 1 && $data['use_child_account']) { 30 | return ['code' => 0, 'msg' => '会员不还不是代理,不能使用子账号']; 31 | } 32 | 33 | $count = model\MemberRecharge::where(['member_id' => $member_id])->where('create_time', '>=', date('Y-m-d'))->count(); 34 | 35 | if ($count > 20) { 36 | return ['code' => 0, 'msg' => '今天创建了太多充值订单']; 37 | } 38 | 39 | if (!isset(model\MemberRecharge::$mnoeys[$data['goods_method']])) { 40 | return ['code' => 0, 'msg' => '未知套餐']; 41 | } 42 | 43 | $money = model\MemberRecharge::$mnoeys[$data['goods_method']]; 44 | 45 | $rechargeModel = new model\MemberRecharge(); 46 | 47 | $sdata = [ 48 | 'order_sn' => 'rc' . date('YmdHis') . mt_rand(100, 999), 49 | 'member_id' => $member_id, 50 | 'account' => $money['money'], 51 | 'money' => $money['money'], 52 | 'pay_time' => null, 53 | 'pay_code' => '', 54 | 'pay_status' => 0, 55 | 'pkg_id' => 0, 56 | 'remark' => isset($data['remark']) ? $data['remark'] : '', 57 | 'create_time' => date('Y-m-d H:i:s'), 58 | 'transaction_id' => '', 59 | 'goods_method' => $data['goods_method'], 60 | 'buy_num' => $money['buy_num'], 61 | 'first_leader' => $member['first_leader'], 62 | ]; 63 | 64 | $res = $rechargeModel->save($sdata); 65 | 66 | if (!$res) { 67 | return ['code' => 0, 'msg' => '创建充值订单失败']; 68 | } 69 | 70 | if ($sdata['account'] == 0) {//待支付金额为0,自动支付成功 71 | $logic = new PaymentLogic; 72 | $logic->rechargePaySuccess($rechargeModel['id'], ['pay_code' => 'other']); 73 | } 74 | 75 | return ['code' => 1, 'msg' => 'ok', 'recharge_id' => $rechargeModel['id']]; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/common/logic/ShippingLogic.php: -------------------------------------------------------------------------------- 1 | 'require|number|>:0', 24 | 'city|城市' => 'require|number|gt:0', 25 | 'area|地区' => 'require|number|gt:0', 26 | 'town|街道' => 'number', 27 | ]); 28 | 29 | if (true !== $v->check($address->toArray())) { 30 | return ['code' => 0, 'msg' => '参数有误-' . $v->getError()]; 31 | } 32 | 33 | $shippingComModel = new model\ShippingCom(); 34 | $areaItemModel = new model\ShippingAreaItem(); 35 | 36 | $shipping_com = $shippingComModel->where(['code' => $shipping_code])->find(); 37 | 38 | if (!$shipping_com) { 39 | return ['code' => 0, 'msg' => '物流公司编码有误']; 40 | } 41 | 42 | if ($shipping_com['enable'] == 0) { 43 | return ['code' => 0, 'msg' => '物流公司[' . $shipping_com['name'] . ']未启用']; 44 | } 45 | 46 | $item = null; 47 | 48 | if ($address['town']) { 49 | $item = $areaItemModel->alias('item')->join('shipping_area area', 'item.area_id=area.id') 50 | ->where(['item.town' => $address['town'], 'area.enable' => 1]) 51 | ->whereLike('area.com_codes', '%,' . $shipping_code . ',%') 52 | ->field('item.*,area.first_weight,money,second_weight,add_money')->find(); 53 | } 54 | if (!$item) { 55 | $item = $areaItemModel->alias('item')->join('shipping_area area', 'item.area_id=area.id') 56 | ->where(['item.area' => $address['area'], 'item.town' => 0, 'area.enable' => 1]) 57 | ->whereLike('area.com_codes', '%,' . $shipping_code . ',%') 58 | ->field('item.*,area.first_weight,money,second_weight,add_money')->find(); 59 | } 60 | if (!$item) { 61 | $item = $areaItemModel->alias('item')->join('shipping_area area', 'item.area_id=area.id') 62 | ->where(['item.city' => $address['city'], 'item.area' => 0, 'area.enable' => 1]) 63 | ->whereLike('area.com_codes', '%,' . $shipping_code . ',%') 64 | ->field('item.*,area.first_weight,money,second_weight,add_money')->find(); 65 | } 66 | if (!$item) { 67 | $item = $areaItemModel->alias('item')->join('shipping_area area', 'item.area_id=area.id') 68 | ->where(['item.province' => $address['province'], 'item.city' => 0, 'area.enable' => 1]) 69 | ->whereLike('area.com_codes', '%,' . $shipping_code . ',%') 70 | ->field('item.*,area.first_weight,money,second_weight,add_money')->find(); 71 | } 72 | if (!$item) { 73 | $item = $areaItemModel->where(['item.province' => 0, 'area.enable' => 1]) 74 | ->alias('item')->join('shipping_area area', 'item.area_id=area.id') 75 | ->whereLike('area.com_codes', '%,' . $shipping_code . ',%') 76 | ->field('item.*,area.first_weight,money,second_weight,add_money')->find(); 77 | } 78 | if (!$item) { 79 | return ['code' => 0, 'msg' => '未找到匹配的物流规则', 'address' => $address]; 80 | } 81 | 82 | if ($weight <= $item['first_weight']) { 83 | return ['code' => 1, 'msg' => 'ok', 'money' => $item['money'], 'area_config' => $item, 'shipping_com' => $shipping_com]; 84 | } 85 | 86 | if ($item['second_weight'] <= 0 || $item['add_money'] <= 0) { 87 | return ['code' => 1, 'msg' => 'ok', 'money' => $item['money'], 'area_config' => $item, 'shipping_com' => $shipping_com]; 88 | } 89 | 90 | $weight = $weight - $item['first_weight']; // 续重 91 | $weight = ceil($weight / $item['second_weight']); // 续重不够取整 92 | 93 | $money = $item['money'] + $weight * $item['add_money']; // 首重 + 续重 * 续重费 94 | 95 | return ['code' => 1, 'msg' => 'ok', 'money' => $money, 'area_config' => $item, 'shipping_com' => $shipping_com]; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/common/model/AgentLevel.php: -------------------------------------------------------------------------------- 1 | count(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/common/model/CmsBanner.php: -------------------------------------------------------------------------------- 1 | belongsTo(CmsPosition::class, 'position_id', 'id'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/common/model/CmsCategory.php: -------------------------------------------------------------------------------- 1 | $data['parent_id']])->max('sort') + 5; 18 | } 19 | } 20 | 21 | public static function onBeforeWrite($data) 22 | { 23 | if (isset($data['parent_id'])) { 24 | if ($data['parent_id'] == 0) { 25 | $data['deep'] = 1; 26 | $data['path'] = ','; 27 | } else { 28 | $parent = static::find($data['parent_id']); 29 | if ($parent) { 30 | $data['deep'] = $parent['deep'] + 1; 31 | $data['path'] = $parent['path'] . $data['parent_id'] . ','; 32 | } 33 | } 34 | } 35 | } 36 | 37 | public static function onAfterDelete($data) 38 | { 39 | static::where(['parent_id' => $data['id']])->update(['parent_id' => $data['parent_id']]); 40 | CmsContent::where(['category_id' => $data['id']])->update(['category_id' => $data['parent_id']]); 41 | } 42 | 43 | protected function treeInit() 44 | { 45 | $this->treeTextField = 'name'; 46 | $this->treeSortField = 'sort'; 47 | } 48 | 49 | public function getContentCountAttr($value, $data) 50 | { 51 | return CmsContent::where('category_id', $data['id'])->count(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/common/model/CmsContent.php: -------------------------------------------------------------------------------- 1 | belongsTo(CmsCategory::class, 'category_id', 'id'); 21 | } 22 | 23 | public function getCategoryAttr($value, $data) 24 | { 25 | $category = CmsCategory::find($data['category_id']); 26 | return $category ? $category['name'] : '--'; 27 | } 28 | 29 | public function getAttrAttr($value, $data) 30 | { 31 | $attr = []; 32 | if ($data['is_recommend']) { 33 | $attr[] = 'is_recommend'; 34 | } 35 | if ($data['is_hot']) { 36 | $attr[] = 'is_hot'; 37 | } 38 | if ($data['is_top']) { 39 | $attr[] = 'is_top'; 40 | } 41 | 42 | return $attr; 43 | } 44 | 45 | public function setTagsAttr($value) 46 | { 47 | if (empty($value)) { 48 | return ''; 49 | } 50 | 51 | return is_array($value) ? ',' . implode(',', $value) . ',' : ',' . trim($value, ',') . ','; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/common/model/CmsPosition.php: -------------------------------------------------------------------------------- 1 | $data['id']])->update(['position_id' => 0]); 21 | } 22 | 23 | public function getBannerCountAttr($value, $data) 24 | { 25 | return CmsBanner::where('position_id', $data['id'])->count(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/common/model/CmsTag.php: -------------------------------------------------------------------------------- 1 | $data['province']])->find(); 23 | 24 | if ($province) { 25 | 26 | $text = $province['ext_name']; 27 | $city = Areacity::where(['id' => $data['city']])->find(); 28 | 29 | if ($city) { 30 | 31 | $text .= ',' . $city['ext_name']; 32 | $area = Areacity::where(['id' => $data['area']])->find(); 33 | 34 | if ($area) { 35 | 36 | $text .= ',' . $area['ext_name']; 37 | 38 | $town = Areacity::where(['id' => $data['town']])->find(); 39 | 40 | if ($town) { 41 | 42 | $text .= ',' . $town['ext_name']; 43 | } 44 | } 45 | } 46 | } 47 | 48 | return $text; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/common/model/Member.php: -------------------------------------------------------------------------------- 1 | find(); 18 | if ($level) { 19 | return $level['name']; 20 | } 21 | 22 | if ($data['level'] == 0) { 23 | return '普通会员'; 24 | } 25 | 26 | return '--'; 27 | } 28 | 29 | public function getHasAvatarAttr($value, $data) 30 | { 31 | return $data && $data['avatar'] ? $data['avatar'] : '/static/images/touxiang.png'; 32 | } 33 | 34 | public function getAgentLevelNameAttr($value, $data) 35 | { 36 | $level = AgentLevel::where('level', $data['agent_level'])->find(); 37 | if ($level) { 38 | return $level['name']; 39 | } 40 | 41 | if ($data['level'] == 0) { 42 | return '非代理'; 43 | } 44 | 45 | return '--'; 46 | } 47 | 48 | public function getCouponOkAttr($value, $data) 49 | { 50 | return ShopCouponList::where(['member_id' => $data['id']])->where(['coupon_type_id' => 1, 'status' => 1, 'order_id' => 0])->count(); 51 | } 52 | 53 | public function getPcaAttr($value, $data) 54 | { 55 | $text = '---'; 56 | 57 | $province = Areacity::where(['id' => $data['province']])->find(); 58 | 59 | if ($province) { 60 | 61 | $text = $province['ext_name']; 62 | $city = Areacity::where(['id' => $data['city']])->find(); 63 | 64 | if ($city) { 65 | 66 | $text .= ',' . $city['ext_name']; 67 | $area = Areacity::where(['id' => $data['area']])->find(); 68 | 69 | if ($area) { 70 | 71 | $text .= ',' . $area['ext_name']; 72 | } 73 | } 74 | } 75 | 76 | return $text; 77 | } 78 | 79 | public function getIdNameAttr($value, $data) 80 | { 81 | return $data['id'] . '#' . $data['nickname']; 82 | } 83 | 84 | public function getLeaderAttr($value, $data) 85 | { 86 | $leader = static::where('id', $data['first_leader'])->find(); 87 | return $leader ? $leader['id_name'] : '--'; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/common/model/MemberAccount.php: -------------------------------------------------------------------------------- 1 | '积分', 15 | 'money' => '余额', 16 | 'commission' => '佣金', 17 | ]; 18 | 19 | public function getNicknameAttr($value, $data) 20 | { 21 | $member = Member::find($data['member_id']); 22 | return $data['member_id'] . '#' . ($member ? $member['nickname'] : '--'); 23 | } 24 | 25 | public function getUsernameAttr($value, $data) 26 | { 27 | $member = Member::find($data['member_id']); 28 | return $data['member_id'] . '#' . ($member ? $member['username'] : '--'); 29 | } 30 | 31 | public static function getNames() 32 | { 33 | $names = implode('/', array_values(self::$types)); 34 | 35 | return $names; 36 | } 37 | 38 | public function member() 39 | { 40 | return $this->belongsTo(Member::class, 'member_id', 'id'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/common/model/MemberAddress.php: -------------------------------------------------------------------------------- 1 | $data['province']])->find(); 23 | 24 | if ($province) { 25 | 26 | $text .= $province['ext_name']; 27 | $city = Areacity::where(['id' => $data['city']])->find(); 28 | 29 | if ($city) { 30 | 31 | $text .= ',' . $city['ext_name']; 32 | $area = Areacity::where(['id' => $data['area']])->find(); 33 | 34 | if ($area) { 35 | 36 | $text .= ',' . $area['ext_name']; 37 | 38 | $town = Areacity::where(['id' => $data['town']])->find(); 39 | 40 | if ($town) { 41 | 42 | $text .= ',' . $town['ext_name']; 43 | } 44 | } 45 | } 46 | } 47 | 48 | return $text; 49 | } 50 | 51 | public function toData() 52 | { 53 | $data = [ 54 | 'consignee' => 0, 55 | 'province' => 0, 56 | 'city' => 0, 57 | 'area' => 0, 58 | 'town' => 0, 59 | 'address' => $this->address, 60 | 'mobile' => $this->mobile, 61 | ]; 62 | 63 | $province = Areacity::where(['id' => $this->province])->find(); 64 | if ($province) { 65 | $data['province'] = $province['ext_name']; 66 | $city = Areacity::where(['id' => $this->province])->find(); 67 | if ($city) { 68 | $data['city'] = $city['ext_name']; 69 | $area = Areacity::where(['id' => $this->area])->find(); 70 | if ($area) { 71 | $data['area'] = $area['ext_name']; 72 | $town = Areacity::where(['id' => $this->town])->find(); 73 | if ($town) { 74 | $data['town'] = $town['ext_name']; 75 | } 76 | } 77 | } 78 | } 79 | 80 | return $data; 81 | } 82 | 83 | public function member() 84 | { 85 | return $this->belongsTo(Member::class, 'member_id', 'id'); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/common/model/MemberCation.php: -------------------------------------------------------------------------------- 1 | count(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/common/model/MemberLog.php: -------------------------------------------------------------------------------- 1 | belongsTo(Member::class, 'member_id', 'id'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/common/model/MemberPayment.php: -------------------------------------------------------------------------------- 1 | '银行卡', 28 | self::PAYMENT_TYPE_ALIPAY => '支付宝', 29 | self::PAYMENT_TYPE_WX => '微信', 30 | ]; 31 | 32 | public function getNicknameAttr($value, $data) 33 | { 34 | $member = Member::find($data['member_id']); 35 | return $data['member_id'] . '#' . ($member ? $member['nickname'] : '--'); 36 | } 37 | 38 | public function getUsernameAttr($value, $data) 39 | { 40 | $member = Member::find($data['member_id']); 41 | return $data['member_id'] . '#' . ($member ? $member['username'] : '--'); 42 | } 43 | 44 | public function getAccountInfoAttr($value, $data) 45 | { 46 | if ($data['payment_type'] == self::PAYMENT_TYPE_BANK) { 47 | return '卡号:' . $data['pay_card_id'] . ',开户行:' . $data['pay_account'] . ',姓名:' . $data['member_name']; 48 | } else if ($data['payment_type'] == self::PAYMENT_TYPE_ALIPAY) { 49 | return '支付宝账户:' . $data['alipay_account'] . ',姓名:' . $data['member_name']; 50 | } else if ($data['payment_type'] == self::PAYMENT_TYPE_WX) { 51 | return '微信账户:' . $data['openid'] . ($data['is_h5'] ? ',h5' : ',app') . ',姓名:' . $data['member_name']; 52 | } 53 | 54 | return '未知支付类型'; 55 | } 56 | 57 | public function member() 58 | { 59 | return $this->belongsTo(Member::class, 'member_id', 'id'); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/common/model/MemberRecharge.php: -------------------------------------------------------------------------------- 1 | '未支付', 42 | self::PAY_STATUS_1 => '已支付', 43 | self::PAY_STATUS_2 => '交易关闭', 44 | ]; 45 | 46 | public static $pay_codes = [ 47 | self::PAY_CODE_WX_PAY => '微信支付', 48 | self::PAY_CODE_ALI_PAY => '支付宝', 49 | self::PAY_CODE_OTHER => '其他', 50 | ]; 51 | 52 | public static $get_goods_methds = [ 53 | self::GET_GOODS_METHOD_1 => '套餐一:消费99元 1份产品,赠100积分', 54 | self::GET_GOODS_METHOD_2 => '套餐二:消费999元 10份产品,赠1100积分', 55 | ]; 56 | 57 | public static $mnoeys = [ 58 | self::GET_GOODS_METHOD_1 => ['money' => 99, 'coupon' => 1, 'points' => 100, 'buy_num' => 1], 59 | self::GET_GOODS_METHOD_2 => ['money' => 999, 'coupon' => 10, 'points' => 1100, 'buy_num' => 10], 60 | ]; 61 | 62 | public function getNicknameAttr($value, $data) 63 | { 64 | $member = Member::find($data['member_id']); 65 | return $data['member_id'] . '#' . ($member ? $member['nickname'] : '--'); 66 | } 67 | 68 | public function getUsernameAttr($value, $data) 69 | { 70 | $member = Member::find($data['member_id']); 71 | return $data['member_id'] . '#' . ($member ? $member['username'] : '--'); 72 | } 73 | 74 | public function getFirstLeaderNameAttr($value, $data) 75 | { 76 | $member = Member::find($data['first_leader']); 77 | return $data['first_leader'] . '#' . ($member ? $member['nickname'] : '--'); 78 | } 79 | 80 | public function member() 81 | { 82 | return $this->belongsTo(Member::class, 'member_id', 'id'); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/common/model/ShippingArea.php: -------------------------------------------------------------------------------- 1 | $data['id']])->delete(); 14 | } 15 | 16 | public function getPcatAttr($value, $data) 17 | { 18 | $itemList = ShippingAreaItem::where(['area_id' => $data['id']])->select(); 19 | 20 | if (!count($itemList)) { 21 | return ''; 22 | } 23 | 24 | $texts = []; 25 | $n = 0; 26 | foreach ($itemList as $item) { 27 | $n += 1; 28 | $texts[] = $item['pcat']; 29 | if ($n > 6) { 30 | $n = 0; 31 | $texts[] = '
'; 32 | } 33 | } 34 | 35 | return implode(' * ', $texts); 36 | } 37 | 38 | public function getComNamesAttr($value, $data) 39 | { 40 | if (empty($data['com_codes'])) { 41 | return '--'; 42 | } 43 | 44 | $coms = ShippingCom::where('code', 'in', trim($data['com_codes'], ','))->where('enable', 1)->column('name'); 45 | 46 | return implode(',', $coms); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/common/model/ShippingAreaItem.php: -------------------------------------------------------------------------------- 1 | $data['province']])->find(); 17 | 18 | if ($province) { 19 | 20 | $text .= $province['ext_name']; 21 | $city = Areacity::where(['id' => $data['city']])->find(); 22 | 23 | if ($city) { 24 | 25 | $text .= '-' . $city['ext_name']; 26 | $area = Areacity::where(['id' => $data['area']])->find(); 27 | 28 | if ($area) { 29 | 30 | $text .= '-' . $area['ext_name']; 31 | 32 | $town = Areacity::where(['id' => $data['town']])->find(); 33 | 34 | if ($town) { 35 | 36 | $text .= '-' . $town['ext_name']; 37 | } 38 | } 39 | } 40 | } 41 | 42 | if ($data['province'] == 0) { 43 | $text = '全国默认'; 44 | } 45 | 46 | return $text; 47 | } 48 | 49 | public function getComNamesAttr($value, $data) 50 | { 51 | if (empty($data['com_codes'])) { 52 | return '--'; 53 | } 54 | 55 | $coms = ShippingCom::where('code', 'in', trim($data['com_codes'], ','))->column('name'); 56 | 57 | return implode(',', $coms); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/common/model/ShippingCom.php: -------------------------------------------------------------------------------- 1 | $data['parent_id']])->max('sort') + 5; 18 | } 19 | } 20 | 21 | public static function onBeforeWrite($data) 22 | { 23 | if (isset($data['parent_id'])) { 24 | if ($data['parent_id'] == 0) { 25 | $data['deep'] = 1; 26 | $data['path'] = ','; 27 | } else { 28 | $parent = static::find($data['parent_id']); 29 | if ($parent) { 30 | $data['deep'] = $parent['deep'] + 1; 31 | $data['path'] = $parent['path'] . $data['parent_id'] . ','; 32 | } 33 | } 34 | } 35 | } 36 | 37 | public static function onAfterDelete($data) 38 | { 39 | static::where(['parent_id' => $data['id']])->update(['parent_id' => $data['parent_id']]); 40 | CmsContent::where(['brand_id' => $data['id']])->update(['brand_id' => $data['parent_id']]); 41 | } 42 | 43 | public function getGoodsCountAttr($value, $data) 44 | { 45 | return ShopGoods::where('brand_id', $data['id'])->count(); 46 | } 47 | 48 | protected function treeInit() 49 | { 50 | $this->treeTextField = 'name'; 51 | $this->treeSortField = 'sort'; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/common/model/ShopCart.php: -------------------------------------------------------------------------------- 1 | $data['parent_id']])->max('sort') + 5; 18 | } 19 | } 20 | 21 | public static function onBeforeWrite($data) 22 | { 23 | if (isset($data['parent_id'])) { 24 | if ($data['parent_id'] == 0) { 25 | $data['deep'] = 1; 26 | $data['path'] = ','; 27 | } else { 28 | $parent = static::find($data['parent_id']); 29 | if ($parent) { 30 | $data['deep'] = $parent['deep'] + 1; 31 | $data['path'] = $parent['path'] . $data['parent_id'] . ','; 32 | } 33 | } 34 | } 35 | } 36 | 37 | public static function onAfterDelete($data) 38 | { 39 | static::where(['parent_id' => $data['id']])->update(['parent_id' => $data['parent_id']]); 40 | ShopGoods::where(['category_id' => $data['id']])->update(['category_id' => $data['parent_id']]); 41 | } 42 | 43 | public function getGoodsCountAttr($value, $data) 44 | { 45 | return ShopGoods::where('category_id', $data['id'])->count(); 46 | } 47 | 48 | protected function treeInit() 49 | { 50 | $this->treeTextField = 'name'; 51 | $this->treeSortField = 'sort'; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/common/model/ShopCouponList.php: -------------------------------------------------------------------------------- 1 | $data['coupon_type_id']])->setInc('del_num'); 19 | } 20 | 21 | public function getNicknameAttr($value, $data) 22 | { 23 | $member = Member::find($data['member_id']); 24 | return $data['member_id'] . '#' . ($member ? $member['nickname'] : '--'); 25 | } 26 | 27 | public function getUsernameAttr($value, $data) 28 | { 29 | $member = Member::find($data['member_id']); 30 | return $data['member_id'] . '#' . ($member ? $member['username'] : '--'); 31 | } 32 | 33 | public function getTypeNameAttr($value, $data) 34 | { 35 | $type = ShopCouponType::find($data['coupon_type_id']); 36 | return $type ? $type['name'] : '--'; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/common/model/ShopCouponType.php: -------------------------------------------------------------------------------- 1 | $data['id']])->where('order_id', '>', 0)->count(); 26 | return $count; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/common/model/ShopGoods.php: -------------------------------------------------------------------------------- 1 | belongsTo('shop_category', 'category_id', 'id'); 33 | } 34 | 35 | public function getAdminGroupAttr($value, $data) 36 | { 37 | $model = new \tpext\myadmin\admin\model\AdminUser; 38 | $model = $model->getAdminGroupModel(); 39 | $category = $model->find($data['admin_group_id']); 40 | return $category ? $category['name'] : '--'; 41 | } 42 | 43 | public function setTags($value) 44 | { 45 | if (empty($value)) { 46 | return ''; 47 | } 48 | 49 | return is_array($value) ? ',' . implode(',', $value) . ',' : ',' . trim($value, ',') . ','; 50 | } 51 | 52 | public function getAttrAttr($value, $data) 53 | { 54 | $attr = []; 55 | if ($data['is_recommend']) { 56 | $attr[] = 'is_recommend'; 57 | } 58 | if ($data['is_hot']) { 59 | $attr[] = 'is_hot'; 60 | } 61 | if ($data['is_top']) { 62 | $attr[] = 'is_top'; 63 | } 64 | 65 | return $attr; 66 | } 67 | 68 | public function getSpuAttr($value, $data) 69 | { 70 | if (empty($value) && isset($data['id'])) { 71 | return 'sp' . str_pad($data['id'], 7, "0", STR_PAD_LEFT); 72 | } 73 | 74 | return $value; 75 | } 76 | 77 | public function getManyPriceAttr($value, $data) 78 | { 79 | return ShopGoodsSpecPrice::where(['goods_id' => $data['id']])->count() > 0 ? 1 : 0; 80 | } 81 | 82 | public function category() 83 | { 84 | return $this->belongsTo(Shopcategory::class, 'category_id', 'id'); 85 | } 86 | 87 | public function brand() 88 | { 89 | return $this->belongsTo(Shopbrand::class, 'brand_id', 'id'); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/common/model/ShopGoodsAttr.php: -------------------------------------------------------------------------------- 1 | $data['goods_id']])->max('sort') + 1; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/common/model/ShopGoodsSpec.php: -------------------------------------------------------------------------------- 1 | $data['goods_id']])->max('sort') + 1; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/common/model/ShopGoodsSpecPrice.php: -------------------------------------------------------------------------------- 1 | '待确认', 95 | self::ORDER_STATUS_1 => '已确认', 96 | self::ORDER_STATUS_2 => '已收货', 97 | self::ORDER_STATUS_3 => '已取消', 98 | self::ORDER_STATUS_4 => '已完成', 99 | self::ORDER_STATUS_5 => '已作废', 100 | ]; 101 | 102 | public static $shipping_status_types = [ 103 | self::SHIPPING_STATUS_0 => '未发货', 104 | self::SHIPPING_STATUS_1 => '已发货', 105 | self::SHIPPING_STATUS_2 => '部分发货', 106 | ]; 107 | 108 | public static $pay_status_types = [ 109 | self::PAY_STATUS_0 => '未支付', 110 | self::PAY_STATUS_1 => '已支付', 111 | self::PAY_STATUS_2 => '申请退款', 112 | self::PAY_STATUS_3 => '退款通过', 113 | self::PAY_STATUS_4 => '退款未通过', 114 | ]; 115 | 116 | public static $prom_types = [ 117 | self::PROM_TYPE_1 => '默认', 118 | self::PROM_TYPE_2 => '抢购', 119 | self::PROM_TYPE_3 => '团购', 120 | self::PROM_TYPE_4 => '优惠', 121 | self::PROM_TYPE_5 => '砍价', 122 | ]; 123 | 124 | public static $pay_codes = [ 125 | self::PAY_CODE_WX_PAY => '微信支付', 126 | self::PAY_CODE_ALI_PAY => '支付宝', 127 | self::PAY_CODE_COD => '货到付款', 128 | self::PAY_CODE_OTHER => '其他', 129 | ]; 130 | 131 | public static $orders_status_desc = [ 132 | self::ORDER_STATUS_DESC_WAITPAY => '待支付', 133 | self::ORDER_STATUS_DESC_WAITSEND => '待发货', 134 | self::ORDER_STATUS_DESC_WAITRECEIVE => '待收货', 135 | self::ORDER_STATUS_DESC_WAITCCOMMENT => '待评价', 136 | self::ORDER_STATUS_DESC_CANCEL => '已取消', 137 | self::ORDER_STATUS_DESC_FINISH => '已完成', 138 | self::ORDER_STATUS_DESC_CANCELLED => '已作废', 139 | ]; 140 | 141 | public static function onAfterDelete($data) 142 | { 143 | //ShopOrderGoods::where(['order_id' => $data['id'], 'is_send' => 0])->delete(); 144 | } 145 | 146 | public function getNicknameAttr($value, $data) 147 | { 148 | $member = Member::find($data['member_id']); 149 | return $member ? $member['nickname'] : '会员不存在'; 150 | } 151 | 152 | public function getPcatAttr($value, $data) 153 | { 154 | $text = '---'; 155 | 156 | $province = Areacity::where(['id' => $data['province']])->find(); 157 | 158 | if ($province) { 159 | 160 | $text = $province['ext_name']; 161 | $city = Areacity::where(['id' => $data['city']])->find(); 162 | 163 | if ($city) { 164 | 165 | $text .= ',' . $city['ext_name']; 166 | $area = Areacity::where(['id' => $data['area']])->find(); 167 | 168 | if ($area) { 169 | 170 | $text .= ',' . $area['ext_name']; 171 | 172 | $town = Areacity::where(['id' => $data['town']])->find(); 173 | 174 | if ($town) { 175 | 176 | $text .= ',' . $town['ext_name']; 177 | } 178 | } 179 | } 180 | } 181 | 182 | return $text; 183 | } 184 | 185 | public function getGoodsNamesAttr($value, $data) 186 | { 187 | $goods = ShopOrderGoods::where(['order_id' => $data['id']])->field('goods_name,spec_key_name,goods_num')->select(); 188 | $names = []; 189 | foreach ($goods as $g) { 190 | $names[] = $g['goods_name'] . ($g['spec_key_name'] ? '(' . $g['spec_key_name'] . ')' : '') . ' X ' . $g['goods_num']; 191 | } 192 | return implode('、', $names); 193 | } 194 | 195 | public function member() 196 | { 197 | return $this->belongsTo(Member::class, 'member_id', 'id'); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /app/common/model/ShopOrderAction.php: -------------------------------------------------------------------------------- 1 | belongsTo(Shoporder::class, 'order_id', 'id'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/common/model/ShopOrderDelivery.php: -------------------------------------------------------------------------------- 1 | belongsTo(Shoporder::class, 'order_id', 'id'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/common/model/ShopOrderGoods.php: -------------------------------------------------------------------------------- 1 | belongsTo(Shoporder::class, 'order_id', 'id'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/common/model/ShopTag.php: -------------------------------------------------------------------------------- 1 | 'webman']); 17 | } 18 | 19 | public function json(Request $request) 20 | { 21 | return json(['code' => 0, 'msg' => 'ok']); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /app/functions.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | namespace app\middleware; 16 | 17 | use Webman\MiddlewareInterface; 18 | use Webman\Http\Response; 19 | use Webman\Http\Request; 20 | 21 | /** 22 | * Class StaticFile 23 | * @package app\middleware 24 | */ 25 | class StaticFile implements MiddlewareInterface 26 | { 27 | public function process(Request $request, callable $next): Response 28 | { 29 | // Access to files beginning with. Is prohibited 30 | if (strpos($request->path(), '/.') !== false) { 31 | return response('

403 forbidden

', 403); 32 | } 33 | /** @var Response $response */ 34 | $response = $next($request); 35 | // Add cross domain HTTP header 36 | /*$response->withHeaders([ 37 | 'Access-Control-Allow-Origin' => '*', 38 | 'Access-Control-Allow-Credentials' => 'true', 39 | ]);*/ 40 | return $response; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/model/Test.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | webman 9 | 10 | 11 | 12 | hello 13 | 14 | 15 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "workerman/webman", 3 | "type": "project", 4 | "keywords": [ 5 | "high performance", 6 | "http service" 7 | ], 8 | "homepage": "http://www.workerman.net", 9 | "license": "MIT", 10 | "description": "High performance HTTP Service Framework.", 11 | "authors": [ 12 | { 13 | "name": "walkor", 14 | "email": "walkor@workerman.net", 15 | "homepage": "http://www.workerman.net", 16 | "role": "Developer" 17 | } 18 | ], 19 | "support": { 20 | "email": "walkor@workerman.net", 21 | "issues": "https://github.com/walkor/webman/issues", 22 | "forum": "http://wenda.workerman.net/", 23 | "wiki": "http://workerman.net/doc/webman", 24 | "source": "https://github.com/walkor/webman" 25 | }, 26 | "require": { 27 | "php": ">=7.2", 28 | "workerman/webman-framework": "^1.4.6", 29 | "monolog/monolog": "^2.0", 30 | "ichynul/tpextmyadmin": "^4.1.1", 31 | "ichynul/tpextareacity": "^1.2" 32 | }, 33 | "suggest": { 34 | "ext-event": "For better performance. " 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "": "./", 39 | "App\\": "./app" 40 | }, 41 | "files": [ 42 | "./support/helpers.php" 43 | ], 44 | "psr-0": { 45 | "": "extend/" 46 | } 47 | }, 48 | "scripts": { 49 | "post-package-install": [ 50 | "support\\Plugin::install" 51 | ], 52 | "post-package-update": [ 53 | "support\\Plugin::install" 54 | ], 55 | "pre-package-uninstall": [ 56 | "support\\Plugin::uninstall" 57 | ] 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /config/app.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | use support\Request; 16 | 17 | return [ 18 | 'debug' => true, 19 | 'default_timezone' => 'Asia/Shanghai', 20 | 'request_class' => Request::class, 21 | 'public_path' => base_path() . DIRECTORY_SEPARATOR . 'public', 22 | 'runtime_path' => base_path(false) . DIRECTORY_SEPARATOR . 'runtime', 23 | 'controller_suffix' => '', 24 | ]; 25 | -------------------------------------------------------------------------------- /config/autoload.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | return [ 16 | 'files' => [ 17 | base_path() . '/app/functions.php', 18 | base_path() . '/support/Request.php', 19 | base_path() . '/support/Response.php', 20 | ] 21 | ]; 22 | -------------------------------------------------------------------------------- /config/bootstrap.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | return [ 16 | support\bootstrap\Session::class, 17 | support\bootstrap\LaravelDb::class, 18 | Webman\ThinkOrm\ThinkOrm::class, 19 | Webman\ThinkCache\ThinkCache::class, 20 | ]; 21 | -------------------------------------------------------------------------------- /config/container.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | return new Webman\Container; -------------------------------------------------------------------------------- /config/database.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | return []; 16 | -------------------------------------------------------------------------------- /config/dependence.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | return []; -------------------------------------------------------------------------------- /config/event.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | return [ 16 | '' => support\exception\Handler::class, 17 | ]; -------------------------------------------------------------------------------- /config/log.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | return [ 16 | 'default' => [ 17 | 'handlers' => [ 18 | [ 19 | 'class' => Monolog\Handler\RotatingFileHandler::class, 20 | 'constructor' => [ 21 | runtime_path() . '/logs/webman.log', 22 | 7, //$maxFiles 23 | Monolog\Logger::DEBUG, 24 | ], 25 | 'formatter' => [ 26 | 'class' => Monolog\Formatter\LineFormatter::class, 27 | 'constructor' => [null, 'Y-m-d H:i:s', true], 28 | ], 29 | ] 30 | ], 31 | ], 32 | ]; 33 | -------------------------------------------------------------------------------- /config/middleware.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | return []; -------------------------------------------------------------------------------- /config/plugin/tpext/core/app.php: -------------------------------------------------------------------------------- 1 | true, 5 | ]; -------------------------------------------------------------------------------- /config/plugin/tpext/core/bootstrap.php: -------------------------------------------------------------------------------- 1 | [ 7 | CrontrollerInit::class 8 | ] 9 | ]; 10 | -------------------------------------------------------------------------------- /config/plugin/tpext/myadmin/app.php: -------------------------------------------------------------------------------- 1 | true, 5 | ]; 6 | -------------------------------------------------------------------------------- /config/plugin/tpext/myadmin/middleware.php: -------------------------------------------------------------------------------- 1 | [ 7 | Auth::class 8 | ] 9 | ]; 10 | -------------------------------------------------------------------------------- /config/plugin/webman/event/app.php: -------------------------------------------------------------------------------- 1 | true, 4 | ]; -------------------------------------------------------------------------------- /config/plugin/webman/event/bootstrap.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | return [ 16 | Webman\Event\BootStrap::class, 17 | ]; 18 | -------------------------------------------------------------------------------- /config/plugin/webman/event/command.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | 16 | return [ 17 | // File update detection and automatic reload 18 | 'monitor' => [ 19 | 'handler' => process\Monitor::class, 20 | 'reloadable' => false, 21 | 'constructor' => [ 22 | // Monitor these directories 23 | 'monitor_dir' => [ 24 | app_path(), 25 | config_path(), 26 | base_path() . '/process', 27 | base_path() . '/support', 28 | base_path() . '/resource', 29 | base_path() . '/.env', 30 | ], 31 | // Files with these suffixes will be monitored 32 | 'monitor_extensions' => [ 33 | 'php', 'html', 'htm', 'env' 34 | ] 35 | ] 36 | ] 37 | ]; 38 | -------------------------------------------------------------------------------- /config/redis.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | return [ 16 | 'default' => [ 17 | 'host' => '127.0.0.1', 18 | 'password' => null, 19 | 'port' => 6379, 20 | 'database' => 0, 21 | ], 22 | ]; 23 | -------------------------------------------------------------------------------- /config/route.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | use Webman\Route; 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /config/server.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | return [ 16 | 'listen' => 'http://0.0.0.0:8787', 17 | 'transport' => 'tcp', 18 | 'context' => [], 19 | 'name' => 'webman', 20 | 'count' => cpu_count() * 2, 21 | 'user' => '', 22 | 'group' => '', 23 | 'reusePort' => false, 24 | 'event_loop' => '', 25 | 'stop_timeout' => 2, 26 | 'pid_file' => runtime_path() . '/webman.pid', 27 | 'status_file' => runtime_path() . '/webman.status', 28 | 'stdout_file' => runtime_path() . '/logs/stdout.log', 29 | 'log_file' => runtime_path() . '/logs/workerman.log', 30 | 'max_package_size' => 10 * 1024 * 1024 31 | ]; 32 | -------------------------------------------------------------------------------- /config/session.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | return [ 16 | 17 | 'type' => 'file', // or redis or redis_cluster 18 | 19 | 'handler' => Webman\FileSessionHandler::class, 20 | 21 | 'config' => [ 22 | 'file' => [ 23 | 'save_path' => runtime_path() . '/sessions', 24 | ], 25 | 'redis' => [ 26 | 'host' => '127.0.0.1', 27 | 'port' => 6379, 28 | 'auth' => '', 29 | 'timeout' => 2, 30 | 'database' => '', 31 | 'prefix' => 'redis_session_', 32 | ], 33 | 'redis_cluster' => [ 34 | 'host' => ['127.0.0.1:7000', '127.0.0.1:7001', '127.0.0.1:7001'], 35 | 'timeout' => 2, 36 | 'auth' => '', 37 | 'prefix' => 'redis_session_', 38 | ] 39 | ], 40 | 41 | 'session_name' => 'PHPSID', 42 | 43 | 'auto_update_timestamp' => false, 44 | 45 | 'lifetime' => 7*24*60*60, 46 | 47 | 'cookie_lifetime' => 365*24*60*60, 48 | 49 | 'cookie_path' => '/', 50 | 51 | 'domain' => '', 52 | 53 | 'http_only' => true, 54 | 55 | 'secure' => false, 56 | 57 | 'same_site' => '', 58 | 59 | 'gc_probability' => [1, 1000], 60 | 61 | ]; 62 | -------------------------------------------------------------------------------- /config/static.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | /** 16 | * Static file settings 17 | */ 18 | return [ 19 | 'enable' => true, 20 | 'middleware' => [ // Static file Middleware 21 | //app\middleware\StaticFile::class, 22 | ], 23 | ]; -------------------------------------------------------------------------------- /config/thinkcache.php: -------------------------------------------------------------------------------- 1 | 'file', 4 | 'stores' => [ 5 | 'file' => [ 6 | 'type' => 'File', 7 | // 缓存保存目录 8 | 'path' => runtime_path() . '/cache/', 9 | // 缓存前缀 10 | 'prefix' => '', 11 | // 缓存有效期 0表示永久缓存 12 | 'expire' => 0, 13 | ], 14 | 'redis' => [ 15 | 'type' => 'redis', 16 | 'host' => '127.0.0.1', 17 | 'port' => 6379, 18 | 'prefix' => '', 19 | 'expire' => 0, 20 | ], 21 | ], 22 | ]; -------------------------------------------------------------------------------- /config/thinkorm.php: -------------------------------------------------------------------------------- 1 | 'mysql', 5 | 'connections' => [ 6 | 'mysql' => [ 7 | // 数据库类型 8 | 'type' => 'mysql', 9 | // 服务器地址 10 | 'hostname' => '127.0.0.1', 11 | // 数据库名 12 | 'database' => 'test', 13 | // 数据库用户名 14 | 'username' => 'root', 15 | // 数据库密码 16 | 'password' => '123456', 17 | // 数据库连接端口 18 | 'hostport' => '3306', 19 | // 数据库连接参数 20 | 'params' => [], 21 | // 数据库编码默认采用utf8 22 | 'charset' => 'utf8', 23 | // 数据库表前缀 24 | 'prefix' => '', 25 | // 断线重连 26 | 'break_reconnect' => true, 27 | // 关闭SQL监听日志 28 | 'trigger_sql' => false, 29 | ], 30 | ], 31 | ]; -------------------------------------------------------------------------------- /config/translation.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | /** 16 | * Multilingual configuration 17 | */ 18 | return [ 19 | // Default language 20 | 'locale' => 'zh_CN', 21 | // Fallback language 22 | 'fallback_locale' => ['zh_CN', 'en'], 23 | // Folder where language files are stored 24 | 'path' => base_path() . '/resource/translations', 25 | ]; -------------------------------------------------------------------------------- /config/view.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | use support\view\Raw; 16 | use support\view\Twig; 17 | use support\view\Blade; 18 | use support\view\ThinkPHP; 19 | 20 | return [ 21 | 'handler' => Raw::class 22 | ]; 23 | -------------------------------------------------------------------------------- /extend/cooladmin/README.md: -------------------------------------------------------------------------------- 1 | ## elementui cool-admin 2 | 3 | ### 基于 [Vue + Element] 对 `tpextmyadmin`的UI替换方案 4 | 5 | ### 部分样式和组件来源于 `cool-admin` : 6 | 7 | # H+admin后台模板样式 8 | 9 | ## 关于 10 | 11 | 替换默认的:`/admin/admin/index`主体页面样式和登录页面`/admin/admin/login`样式 12 | 13 | ## 使用 14 | 15 | 1. 下载安装本扩展 16 | 2. 打开设置:在[平台设置]-[后台框架] 17 | 3. 点击`index主体页面风格`下拉框,选择`COOL-ADMIN样式` 18 | 4. 点击`登录页面风格`下拉框,选择`COOL-ADMIN样式` (可选,登录页面可不换) 19 | 5. [F5]刷新浏览器生效。 -------------------------------------------------------------------------------- /extend/cooladmin/assets/css/index.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["index.scss"],"names":[],"mappings":";AAAA;AAEA;EACI;EACA;EACA;EACA;;;AAIJ;EACI;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;;AAGJ;AAAA;EAGI;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI;EACA;;;AAGJ;AAAA;EAEI;;;AAGJ;EACI;;;AAiBJ;EACI,cAfM;EAgBN,cAbY;EAcZ,aAbW;EAcX,WAbS;EAcT,cAbY;;;AAkBhB;EACI;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;;AAGJ;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAIR;EACI;IACI;IACA;IACA;IACA;;EAIJ;IACI;;EAIA;IACI;;EAGJ;IACI;;;AAKZ;EAEI;AAAA;IAEI;;EAGJ;IACI;;EAIA;IACI;;EAGJ;IACI;;;;AAMhB;EACI;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;;AAIR;EACI;;;AAIR;EACI;;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAGJ;EACI;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAEA;EACI;;AAMhB;EACI;EACA;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;;AAGJ;EACI;EACA;;AAGJ;EACI;;;AAMZ;EACI;;AAEA;EACI;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;;AAGJ;EACI,OAvRA;EAwRA;;AAGJ;EACI;;;AAQR;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;;AAIR;EACI;EACA;EACA;;AAEA;EACI;EACA;EACA;;AAKJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAOZ;EACI;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAMhB;EACI;EACA;;AAEA;EACI;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;EACA;;;AAKZ;AAAA;AAAA;AAAA;EAII;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;AAEA;EAEI;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAIR;EACI;;AAGJ;EACI;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,OAheD;;AAqeH;EACI;;AAKJ;EACI,OA9eA;;AAifJ;EACI,kBAlfA;;AAsfR;EACI;;;AAKZ;EACI;EACA;;AAEA;EACI;EACA;;AAGJ;EACI;;AAKI;EAEI;EACA;;AAIR;EAGI;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;;AAMA;EACI;EACA;;;AAOpB;EACI;;AAKY;EACI;EACA;;AAEA;EACI;EACA;;AAKZ;EACI;EACA;;AAEA;EACI;EACA;;;AAOpB;EACI;;AAGI;EACI;EACA;EACA;EACA;;AAIR;EACI;EACA;EACA;;;AAIR;EACI;;;AAGJ;EACI","file":"index.css"} -------------------------------------------------------------------------------- /extend/cooladmin/assets/css/login.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /** style from COOL-ADMIN **/ 3 | * { 4 | padding: 0; 5 | margin: 0; 6 | outline: none; 7 | font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif; 8 | } 9 | 10 | html, 11 | body, 12 | #app { 13 | height: 100%; 14 | width: 100%; 15 | } 16 | 17 | a { 18 | text-decoration: none; 19 | color: #fff; 20 | } 21 | 22 | input, 23 | button { 24 | outline: none; 25 | } 26 | 27 | input:-webkit-autofill { 28 | box-shadow: 0 0 0px 1000px 2f3447 inset; 29 | } 30 | 31 | .page-login { 32 | height: 100vh; 33 | width: 100vw; 34 | position: relative; 35 | background-color: rgb(44, 44, 44); 36 | } 37 | .page-login .box { 38 | background-color: rgba(44, 44, 44, 0.8888); 39 | border-radius: 10px; 40 | padding-bottom: 20px; 41 | display: flex; 42 | flex-direction: column; 43 | justify-content: center; 44 | align-items: center; 45 | width: 500px; 46 | position: absolute; 47 | left: calc(50% - 250px); 48 | top: calc(50% - 280px); 49 | } 50 | .page-login .box .logo { 51 | max-width: 100%; 52 | margin-bottom: 20px; 53 | margin-top: 30px; 54 | } 55 | .page-login .box .desc { 56 | color: #ccc; 57 | font-size: 12px; 58 | margin-bottom: 10px; 59 | margin-top: 10px; 60 | letter-spacing: 1px; 61 | } 62 | .page-login .box .el-form { 63 | width: 300px; 64 | border-radius: 3px; 65 | } 66 | .page-login .box .el-form .el-form-item { 67 | margin-bottom: 20px; 68 | } 69 | .page-login .box .el-form .el-form-item__label { 70 | color: #ccc; 71 | } 72 | .page-login .box .el-form .el-input .el-input__inner { 73 | border: 0; 74 | border-bottom: 0.5px solid #999; 75 | border-radius: 0; 76 | padding: 0 5px; 77 | background-color: transparent; 78 | color: #ccc; 79 | transition: border-color 0.3s; 80 | position: relative; 81 | } 82 | .page-login .box .el-form .el-input .el-input__inner:focus { 83 | border-color: #fff; 84 | color: #fff; 85 | } 86 | .page-login .box .el-form .el-input .el-input__inner:-webkit-autofill { 87 | -webkit-text-fill-color: #fff !important; 88 | -webkit-box-shadow: 0 0 0px 1000px transparent inset !important; 89 | transition: background-color 50000s ease-in-out 0s; 90 | } 91 | .page-login .box .el-form .captcha { 92 | position: relative; 93 | } 94 | .page-login .box .el-form .captcha .value { 95 | position: absolute; 96 | bottom: 2px; 97 | right: 0; 98 | height: 36px; 99 | cursor: pointer; 100 | } 101 | .page-login .box .el-form .captcha .value img { 102 | height: 100%; 103 | } 104 | .page-login .box .submit-btn { 105 | margin-top: 20px; 106 | border-radius: 30px; 107 | margin-bottom: 10px; 108 | padding: 10px 60px; 109 | color: #000; 110 | } 111 | 112 | /*# sourceMappingURL=login.css.map */ 113 | -------------------------------------------------------------------------------- /extend/cooladmin/assets/css/login.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["login.scss"],"names":[],"mappings":";AAAA;AAEA;EACI;EACA;EACA;EACA;;;AAIJ;AAAA;AAAA;EAGI;EACA;;;AAGJ;EACI;EACA;;;AAGJ;AAAA;EAEI;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;;AAEA;EACI;;AAEA;EACI;;AAKJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;;AAKZ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAMhB;EACI;EACA;EACA;EACA;EACA","file":"login.css"} -------------------------------------------------------------------------------- /extend/cooladmin/assets/css/login.scss: -------------------------------------------------------------------------------- 1 | /** style from COOL-ADMIN **/ 2 | 3 | * { 4 | padding: 0; 5 | margin: 0; 6 | outline: none; 7 | font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", 8 | "微软雅黑", Arial, sans-serif; 9 | } 10 | 11 | html, 12 | body, 13 | #app { 14 | height: 100%; 15 | width: 100%; 16 | } 17 | 18 | a { 19 | text-decoration: none; 20 | color: #fff; 21 | } 22 | 23 | input, 24 | button { 25 | outline: none; 26 | } 27 | 28 | input:-webkit-autofill { 29 | box-shadow: 0 0 0px 1000px 2f3447 inset; 30 | } 31 | 32 | .page-login { 33 | height: 100vh; 34 | width: 100vw; 35 | position: relative; 36 | background-color: rgb(44, 44, 44); 37 | 38 | .box { 39 | background-color: rgba(44, 44, 44,.8888); 40 | border-radius: 10px; 41 | padding-bottom: 20px; 42 | display: flex; 43 | flex-direction: column; 44 | justify-content: center; 45 | align-items: center; 46 | width: 500px; 47 | position: absolute; 48 | left: calc(50% - 250px); 49 | top: calc(50% - 280px); 50 | 51 | .logo { 52 | max-width: 100%; 53 | margin-bottom: 20px; 54 | margin-top: 30px; 55 | } 56 | 57 | .desc { 58 | color: #ccc; 59 | font-size: 12px; 60 | margin-bottom: 10px; 61 | margin-top: 10px; 62 | letter-spacing: 1px; 63 | } 64 | 65 | .el-form { 66 | width: 300px; 67 | border-radius: 3px; 68 | 69 | .el-form-item { 70 | margin-bottom: 20px; 71 | 72 | &__label { 73 | color: #ccc; 74 | } 75 | } 76 | 77 | .el-input { 78 | .el-input__inner { 79 | border: 0; 80 | border-bottom: 0.5px solid #999; 81 | border-radius: 0; 82 | padding: 0 5px; 83 | background-color: transparent; 84 | color: #ccc; 85 | transition: border-color 0.3s; 86 | position: relative; 87 | 88 | &:focus { 89 | border-color: #fff; 90 | color: #fff; 91 | } 92 | 93 | &:-webkit-autofill { 94 | -webkit-text-fill-color: #fff !important; 95 | -webkit-box-shadow: 0 0 0px 1000px transparent inset !important; 96 | transition: background-color 50000s ease-in-out 0s; 97 | } 98 | } 99 | } 100 | 101 | .captcha { 102 | position: relative; 103 | 104 | .value { 105 | position: absolute; 106 | bottom: 2px; 107 | right: 0; 108 | height: 36px; 109 | cursor: pointer; 110 | 111 | img { 112 | height: 100%; 113 | } 114 | } 115 | } 116 | } 117 | 118 | .submit-btn { 119 | margin-top: 20px; 120 | border-radius: 30px; 121 | margin-bottom: 10px; 122 | padding: 10px 60px; 123 | color: #000; 124 | } 125 | } 126 | } -------------------------------------------------------------------------------- /extend/cooladmin/assets/css/readme.md: -------------------------------------------------------------------------------- 1 | scss 转 css : 2 | 3 | 安装 sass 4 | ```bash 5 | npm install sass -g 6 | ```` 7 | 8 | 转换: 9 | ```bash 10 | sass ./login.scss ./login.css 11 | ``` -------------------------------------------------------------------------------- /extend/cooladmin/assets/icon/logo/silder-simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-tpext/mywebman/9d49dc60d7ff7f57539810ce303f0edd736a06bc/extend/cooladmin/assets/icon/logo/silder-simple.png -------------------------------------------------------------------------------- /extend/cooladmin/assets/js/index.js: -------------------------------------------------------------------------------- 1 | function getThemes() { 2 | return [ 3 | { 4 | label: "钴蓝", 5 | name: "blue", 6 | color: "#4165d7" 7 | }, 8 | { 9 | label: "极黑", 10 | name: "black", 11 | color: "#2f3447" 12 | }, 13 | { 14 | label: "果绿", 15 | name: "green", 16 | color: "#51C21A" 17 | }, 18 | { 19 | label: "酱紫", 20 | name: "purple", 21 | color: "#d0378d" 22 | } 23 | ]; 24 | } 25 | 26 | function getBrowser() { 27 | var clientHeight = document.documentElement.clientHeight, clientWidth = document.documentElement.clientWidth; 28 | 29 | // 浏览器信息 30 | var ua = navigator.userAgent.toLowerCase(); 31 | 32 | // 浏览器类型 33 | var type = (ua.match(/firefox|chrome|safari|opera/g) || "other")[0]; 34 | 35 | if ((ua.match(/msie|trident/g) || [])[0]) { 36 | type = "msie"; 37 | } 38 | 39 | // 平台标签 40 | var tag = ""; 41 | 42 | var isTocuh = 43 | "ontouchstart" in window || ua.indexOf("touch") !== -1 || ua.indexOf("mobile") !== -1; 44 | if (isTocuh) { 45 | if (ua.indexOf("ipad") !== -1) { 46 | tag = "pad"; 47 | } else if (ua.indexOf("mobile") !== -1) { 48 | tag = "mobile"; 49 | } else if (ua.indexOf("android") !== -1) { 50 | tag = "androidPad"; 51 | } else { 52 | tag = "pc"; 53 | } 54 | } else { 55 | tag = "pc"; 56 | } 57 | 58 | // 浏览器内核 59 | var prefix = ""; 60 | 61 | switch (type) { 62 | case "chrome": 63 | case "safari": 64 | case "mobile": 65 | prefix = "webkit"; 66 | break; 67 | case "msie": 68 | prefix = "ms"; 69 | break; 70 | case "firefox": 71 | prefix = "Moz"; 72 | break; 73 | case "opera": 74 | prefix = "O"; 75 | break; 76 | default: 77 | prefix = "webkit"; 78 | break; 79 | } 80 | 81 | // 操作平台 82 | var plat = ua.indexOf("android") > 0 ? "android" : navigator.platform.toLowerCase(); 83 | 84 | // 屏幕信息 85 | var screen = "full"; 86 | 87 | if (clientWidth < 768) { 88 | screen = "xs"; 89 | } else if (clientWidth < 992) { 90 | screen = "sm"; 91 | } else if (clientWidth < 1200) { 92 | screen = "md"; 93 | } else if (clientWidth < 1920) { 94 | screen = "xl"; 95 | } else { 96 | screen = "full"; 97 | } 98 | 99 | // 是否 ios 100 | var isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); 101 | 102 | // 浏览器版本 103 | var version = (ua.match(/[\s\S]+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1]; 104 | 105 | // 是否 PC 端 106 | var isPC = tag === "pc"; 107 | 108 | // 是否移动端 109 | var isMobile = isPC ? false : true; 110 | 111 | // 是否移动端 + 屏幕宽过小 112 | var isMini = screen === "xs" || isMobile; 113 | 114 | return { 115 | height: clientHeight, 116 | width: clientWidth, 117 | version, 118 | type, 119 | plat, 120 | tag, 121 | prefix, 122 | isMobile, 123 | isIOS, 124 | isPC, 125 | isMini, 126 | screen 127 | }; 128 | } 129 | 130 | function getSubMenu(treeObj) { 131 | var topMenu = []; 132 | var leftMenu = []; 133 | 134 | for (var i in treeObj) { 135 | var children = treeObj[i].children; 136 | if (!children || !children.length) { 137 | if (treeObj[i].url && treeObj[i].url != '#') { 138 | children = [treeObj[i]]; 139 | } 140 | } 141 | if (children.length) { 142 | leftMenu = leftMenu.concat(children); 143 | } 144 | if (!treeObj[i].is_home) { 145 | delete treeObj[i].children; 146 | topMenu.push(treeObj[i]); 147 | } 148 | } 149 | 150 | return { 151 | left: leftMenu, 152 | top: topMenu, 153 | }; 154 | } 155 | 156 | /** 157 | * @author CSDN 蔚莱先森 158 | * @param source json数据源 159 | * @param id 主键ID 160 | * @param parendId 父级ID名称 161 | * @param children 子级名称 162 | */ 163 | function treeData(source, id, parentId, children) { 164 | var cloneData = (typeof source == 'object') ? source : JSON.parse(source); 165 | return cloneData.filter(function (father) { 166 | var branchArr = cloneData.filter(function (child) { return father[id] == child[parentId] }); 167 | branchArr.length > 0 ? father[children] = branchArr : ''; 168 | return father[parentId] == 0 169 | }) 170 | } 171 | 172 | function isEmpty(value) { 173 | if (isArray(value)) { 174 | return value.length === 0; 175 | } 176 | 177 | if (isObject(value)) { 178 | return Object.keys(value).length === 0; 179 | } 180 | 181 | return value === "" || value === undefined || value === null; 182 | } 183 | 184 | function isArray(value) { 185 | if (typeof Array.isArray === "function") { 186 | return Array.isArray(value); 187 | } else { 188 | return Object.prototype.toString.call(value) === "[object Array]"; 189 | } 190 | } 191 | 192 | function isObject(value) { 193 | return Object.prototype.toString.call(value) === "[object Object]"; 194 | } 195 | 196 | function last(data) { 197 | if (isArray(data) || isString(data)) { 198 | return data[data.length - 1]; 199 | } 200 | } -------------------------------------------------------------------------------- /extend/cooladmin/assets/lib/theme-chalk/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-tpext/mywebman/9d49dc60d7ff7f57539810ce303f0edd736a06bc/extend/cooladmin/assets/lib/theme-chalk/fonts/element-icons.ttf -------------------------------------------------------------------------------- /extend/cooladmin/assets/lib/theme-chalk/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-tpext/mywebman/9d49dc60d7ff7f57539810ce303f0edd736a06bc/extend/cooladmin/assets/lib/theme-chalk/fonts/element-icons.woff -------------------------------------------------------------------------------- /extend/cooladmin/assets/theme/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-tpext/mywebman/9d49dc60d7ff7f57539810ce303f0edd736a06bc/extend/cooladmin/assets/theme/fonts/element-icons.ttf -------------------------------------------------------------------------------- /extend/cooladmin/assets/theme/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-tpext/mywebman/9d49dc60d7ff7f57539810ce303f0edd736a06bc/extend/cooladmin/assets/theme/fonts/element-icons.woff -------------------------------------------------------------------------------- /extend/cooladmin/common/Resource.php: -------------------------------------------------------------------------------- 1 | getRoot() . implode(DIRECTORY_SEPARATOR, ['admin', 'view', 'index', 'index.html']); 25 | $loginView = $this->getRoot() . implode(DIRECTORY_SEPARATOR, ['admin', 'view', 'index', 'login.html']); 26 | 27 | adminModule::getInstance()->addIndexView($indexView, 'COOL-ADMIN样式'); 28 | adminModule::getInstance()->addLoginView($loginView, 'COOL-ADMIN样式'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /extend/extdemo/LICENSE.txt: -------------------------------------------------------------------------------- 1 | LICENSE 内容 2 | 1.是否开源 3 | 2.是否收费 4 | -------------------------------------------------------------------------------- /extend/extdemo/README.md: -------------------------------------------------------------------------------- 1 | 自定义扩展范例: 2 | 3 | 某些情况下,不便于公开通过`composer`来安装扩展,可通过tp框架的`extend`目录来安装扩展。 4 | 5 | 自定义扩展与`composer`扩展目录比较 6 | 7 | 假如有一个`composer`扩展`extdemo`,那么他的目录大概是这样: 8 | 扩展根目录:`wwwroot\vendor\ichynul\extdemo\` 9 | ``` 10 | ── assets (资源,不需则留空,发布时复制到`/public/assets/`) 11 | ├── css 12 | ├── images 13 | └── js 14 | ── data (安装或卸载脚本,不需要安装则留空) 15 | ├── install.sql 16 | └── uninstall.sql 17 | ── src (源码目录) 18 | ├── admin (admin模块) 19 | │ ├── controller 20 | │ ├── ... 21 | │ ├── model 22 | │ ├── ... 23 | └── common 24 | │ └── Module.php (模块定义) 25 | ├── common.php 26 | ├── config.php (扩展自定义配置) 27 | └── helper.php           (扩展加载) 28 | ── composer.json 29 | ── LICENSE.txt 30 | ── README.md 31 | ``` 32 | PS : tp框架的`extend`加载原理。自动查找`extend`目录下的目录和文件,根据目录结构转换为对应的命名空间。 33 | `thinkphp\library\Loader.php` (line:114): 34 | ```php 35 | // 自动加载extend目录 36 | self::addAutoLoadDir($rootPath . 'extend'); 37 | 38 | ``` 39 | 40 | 把它改造为自定义扩展: 41 | 根目录:`wwwroot\extend\extdemo\` 42 | 43 | ``` 44 | ── assets (资源,不需则留空,发布时复制到`/public/assets/`) 45 | ├── css 46 | ├── images 47 | └── js 48 | ── data (安装或卸载脚本,不需要安装则留空) 49 | ├── install.sql 50 | └── uninstall.sql 51 | ── admin (admin模块) 52 | ├──controller 53 | ├──... 54 | ├──model 55 | ├──... 56 | common 57 | └── Module.php (模块定义) 58 | ── config.php (扩展自定义配置) 59 | ── common.php 60 | ── LICENSE.txt 61 | ── README.md 62 | ``` 63 | 改造要点: 64 | 1. 不需要`composer.json`。 65 | 2. 不需要`src`。代码直接放扩展根目录。 66 | 3. 不需要`helper.php`。 67 | 4. 修改`Module.php`中`$root`定义,由于代码从`src`目录往上提了一级,所以: 68 | `protected $root = __DIR__ . '/../../';` 改为: `protected $root = __DIR__ . '/../';` 69 | 5. 由于不能通过`helper.php`来加载扩展,所以需要在【扩展管理】-【tpext基础】的配置中加入`extdemo\common\Module`,刷新。 70 | 6. 修改`LICENSE.txt`文件 71 | 7. 修改`readme.md`,由于自定义插件不能加载其他`composer`扩展,若你的自定义扩展依赖于其他`composer`扩展,可在其中说明需要安装哪些。 72 | 8. 目前只支持一级目录的扩展: 73 | 74 | ``` 75 | ── extend 76 | ├── mymouule1(支持) 77 | ├── mymouule2(支持) 78 | └── hismouule3(支持) 79 | 80 | ``` 81 | 不支持二级的扩展,如: 82 | 83 | ``` 84 | ── extend 85 | └── mymouule 86 | │ ├── mymouule1 (二级目录下不支持) 87 | │ └── mymouule2 (二级目录下不支持) 88 | └── hismouule3(支持) 89 | ``` 90 | 所有如果你同时使用其他人的扩展,给自定义扩展起名是要避免命名冲突 -------------------------------------------------------------------------------- /extend/extdemo/admin/controller/Extdemo.php: -------------------------------------------------------------------------------- 1 | dataModel = new ExtdemoModel; 28 | 29 | $this->pageTitle = '范例'; 30 | } 31 | 32 | /** 33 | * 构建表格 34 | * 35 | * @return void 36 | */ 37 | protected function buildTable(&$data = []) 38 | { 39 | $table = $this->table; 40 | 41 | $table->show('id', 'ID'); 42 | $table->show('create_time', '创建时间'); 43 | $table->show('update_time', '更新时间'); 44 | 45 | $table->getToolbar()->html(''); 46 | 47 | $table->useActionbar(false); 48 | 49 | $table->useCheckbox(false); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /extend/extdemo/admin/model/Extdemo.php: -------------------------------------------------------------------------------- 1 | ['extdemo'], 23 | ]; 24 | 25 | public function configPath() 26 | { 27 | return realpath($this->getRoot() . 'config.php'); 28 | } 29 | 30 | /** 31 | * 后台菜单 32 | * 33 | * @var array 34 | */ 35 | protected $menus = [ 36 | [ 37 | 'title' => '自定义扩展', 38 | 'sort' => 1, 39 | 'url' => '#', 40 | 'icon' => 'mdi mdi-coffee', 41 | 'children' => [ 42 | [ 43 | 'title' => '扩展范例', 44 | 'sort' => 1, 45 | 'url' => '/admin/extdemo/index', 46 | 'icon' => 'mdi mdi-collage', 47 | ] 48 | ], 49 | ] 50 | ]; 51 | } 52 | -------------------------------------------------------------------------------- /extend/extdemo/config.php: -------------------------------------------------------------------------------- 1 | '自定义扩展范例', 5 | 'description' => '可通过tp框架的`extend`目录来安装扩展', 6 | //配置描述 7 | '__config__' => [ 8 | 'name' => ['type' => 'text', 'label' => '名称'], 9 | 'description' => ['type' => 'textarea', 'label' => '描述'] 10 | ], 11 | ]; 12 | -------------------------------------------------------------------------------- /extend/extdemo/data/install.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `__PREFIX__extdemo` ( 2 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', 3 | `create_time` datetime NOT NULL DEFAULT '2020-01-01 00:00:00' COMMENT '添加时间', 4 | `update_time` datetime NOT NULL DEFAULT '2020-01-01 00:00:00' COMMENT '更新时间', 5 | PRIMARY KEY (`id`) 6 | ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='测试表'; 7 | 8 | -- 默认权限 9 | INSERT INTO `__PREFIX__extdemo` (`id`, `create_time`, `update_time`) VALUES 10 | (1, '2020-11-11 11:11:11', '2020-11-11 11:11:11'); -------------------------------------------------------------------------------- /extend/extdemo/data/uninstall.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `__PREFIX__extdemo`; -------------------------------------------------------------------------------- /extend/hplusadmin/README.md: -------------------------------------------------------------------------------- 1 | # H+admin后台模板样式 2 | 3 | ## 关于 4 | 5 | 替换默认的:`/admin/admin/index`主体页面样式和登录页面`/admin/admin/login`样式 6 | 7 | ## 使用 8 | 9 | 1. 下载安装本扩展 10 | 2. 打开设置:在[平台设置]-[后台框架] 11 | 3. 点击`index主体页面风格`下拉框,选择`H+ 后台模板` 12 | 4. 点击`登录页面风格`下拉框,选择`H+ 后台模板` (可选,登录页面可不换) 13 | 5. [F5]刷新浏览器生效。 14 | 15 | ## 注意事项 16 | 17 | 在设置中保存以后会保存模板的绝对路径,当网站根目录路径变化后(服务器搬迁,修改网站路径),设置会重置为默认的`lightYearAdmin`,需要重新打开设置页面修改设置保存。 18 | -------------------------------------------------------------------------------- /extend/hplusadmin/assets/css/login.min.css: -------------------------------------------------------------------------------- 1 | html{height:100%}body.signin{height:auto;background:url(../img/login-background.jpg) no-repeat center fixed;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-size:cover;color:rgba(255,255,255,.95)}.signinpanel{width:750px;margin:10% auto 0}.signinpanel .logopanel{float:none;width:auto;padding:0;background:0 0}.signinpanel .signin-info ul{list-style:none;padding:0;margin:20px 0}.signinpanel .form-control{display:block;margin-top:15px}.signinpanel .uname{background:#fff url(../img/user.png) no-repeat 95% center;color:#333}.signinpanel .pword{background:#fff url(../img/locked.png) no-repeat 95% center;color:#333}.signinpanel .btn{margin-top:15px}.signinpanel form{background:rgba(255,255,255,.2);border:1px solid rgba(255,255,255,.3);-moz-box-shadow:0 3px 0 rgba(12,12,12,.03);-webkit-box-shadow:0 3px 0 rgba(12,12,12,.03);box-shadow:0 3px 0 rgba(12,12,12,.03);-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;padding:30px}.signup-footer{border-top:solid 1px rgba(255,255,255,.3);margin:20px 0;padding-top:15px}@media screen and (max-width:768px){.signinpanel,.signuppanel{margin:0 auto;width:420px!important;padding:20px}.signinpanel form{margin-top:20px}.signup-footer,.signuppanel .form-control{margin-bottom:10px}.signup-footer .pull-left,.signup-footer .pull-right{float:none!important;text-align:center}.signinpanel .signin-info ul{display:none}}@media screen and (max-width:320px){.signinpanel,.signuppanel{margin:0 20px;width:auto}} -------------------------------------------------------------------------------- /extend/hplusadmin/assets/css/patterns/header-profile-skin-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-tpext/mywebman/9d49dc60d7ff7f57539810ce303f0edd736a06bc/extend/hplusadmin/assets/css/patterns/header-profile-skin-1.png -------------------------------------------------------------------------------- /extend/hplusadmin/assets/css/patterns/header-profile-skin-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-tpext/mywebman/9d49dc60d7ff7f57539810ce303f0edd736a06bc/extend/hplusadmin/assets/css/patterns/header-profile-skin-3.png -------------------------------------------------------------------------------- /extend/hplusadmin/assets/css/patterns/header-profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-tpext/mywebman/9d49dc60d7ff7f57539810ce303f0edd736a06bc/extend/hplusadmin/assets/css/patterns/header-profile.png -------------------------------------------------------------------------------- /extend/hplusadmin/assets/css/patterns/shattered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-tpext/mywebman/9d49dc60d7ff7f57539810ce303f0edd736a06bc/extend/hplusadmin/assets/css/patterns/shattered.png -------------------------------------------------------------------------------- /extend/hplusadmin/assets/img/login-background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-tpext/mywebman/9d49dc60d7ff7f57539810ce303f0edd736a06bc/extend/hplusadmin/assets/img/login-background.jpg -------------------------------------------------------------------------------- /extend/hplusadmin/assets/js/contabs.min.js: -------------------------------------------------------------------------------- 1 | $(function(){function t(t){var e=0;return $(t).each(function(){e+=$(this).outerWidth(!0)}),e}function e(e){var a=t($(e).prevAll()),i=t($(e).nextAll()),n=t($(".content-tabs").children().not(".J_menuTabs")),s=$(".content-tabs").outerWidth(!0)-n,r=0;if($(".page-tabs-content").outerWidth()i){r=a;for(var o=e;r-$(o).outerWidth()>$(".page-tabs-content").outerWidth()-s;)r-=$(o).prev().outerWidth(),o=$(o).prev()}}else a>s-$(e).outerWidth(!0)-$(e).prev().outerWidth(!0)&&(r=a-$(e).prev().outerWidth(!0));$(".page-tabs-content").animate({marginLeft:0-r+"px"},"fast")}function a(){var e=Math.abs(parseInt($(".page-tabs-content").css("margin-left"))),a=t($(".content-tabs").children().not(".J_menuTabs")),i=$(".content-tabs").outerWidth(!0)-a,n=0;if($(".page-tabs-content").width()i){for(;r+$(s).outerWidth(!0)0;)r+=$(s).outerWidth(!0),s=$(s).prev();n=t($(s).prevAll())}$(".page-tabs-content").animate({marginLeft:0-n+"px"},"fast")}function i(){var e=Math.abs(parseInt($(".page-tabs-content").css("margin-left"))),a=t($(".content-tabs").children().not(".J_menuTabs")),i=$(".content-tabs").outerWidth(!0)-a,n=0;if($(".page-tabs-content").width()0;)r+=$(s).outerWidth(!0),s=$(s).next();n=t($(s).prevAll()),n>0&&$(".page-tabs-content").animate({marginLeft:0-n+"px"},"fast")}function n(){var t=$(this).attr("href"),a=$(this).data("index"),i=$.trim($(this).text()),n=!0;if(void 0==t||0==$.trim(t).length)return!1;if($(".J_menuTab").each(function(){return $(this).data("id")==t?($(this).hasClass("active")||($(this).addClass("active").siblings(".J_menuTab").removeClass("active"),e(this),$(".J_mainContent .J_iframe").each(function(){return $(this).data("id")==t?($(this).show().siblings(".J_iframe").hide(),!1):void 0})),n=!1,!1):void 0}),n){var s=''+i+' ';$(".J_menuTab").removeClass("active");var r='';$(".J_mainContent").find("iframe.J_iframe").hide().parents(".J_mainContent").append(r);var o=layer.load();setTimeout(function(){layer.close(o)},2000);$(".J_mainContent iframe:visible").load(function(){layer.close(o)}),$(".J_menuTabs .page-tabs-content").append(s),e($(".J_menuTab.active"))}return!1}function s(){var t=$(this).parents(".J_menuTab").data("id"),a=$(this).parents(".J_menuTab").width();if($(this).parents(".J_menuTab").hasClass("active")){if($(this).parents(".J_menuTab").next(".J_menuTab").size()){var i=$(this).parents(".J_menuTab").next(".J_menuTab:eq(0)").data("id");$(this).parents(".J_menuTab").next(".J_menuTab:eq(0)").addClass("active"),$(".J_mainContent .J_iframe").each(function(){return $(this).data("id")==i?($(this).show().siblings(".J_iframe").hide(),!1):void 0});var n=parseInt($(".page-tabs-content").css("margin-left"));0>n&&$(".page-tabs-content").animate({marginLeft:n+a+"px"},"fast"),$(this).parents(".J_menuTab").remove(),$(".J_mainContent .J_iframe").each(function(){return $(this).data("id")==t?($(this).remove(),!1):void 0})}if($(this).parents(".J_menuTab").prev(".J_menuTab").size()){var i=$(this).parents(".J_menuTab").prev(".J_menuTab:last").data("id");$(this).parents(".J_menuTab").prev(".J_menuTab:last").addClass("active"),$(".J_mainContent .J_iframe").each(function(){return $(this).data("id")==i?($(this).show().siblings(".J_iframe").hide(),!1):void 0}),$(this).parents(".J_menuTab").remove(),$(".J_mainContent .J_iframe").each(function(){return $(this).data("id")==t?($(this).remove(),!1):void 0})}}else $(this).parents(".J_menuTab").remove(),$(".J_mainContent .J_iframe").each(function(){return $(this).data("id")==t?($(this).remove(),!1):void 0}),e($(".J_menuTab.active"));return!1}function r(){$(".page-tabs-content").children("[data-id]").not(":first").not(".active").each(function(){$('.J_iframe[data-id="'+$(this).data("id")+'"]').remove(),$(this).remove()}),$(".page-tabs-content").css("margin-left","0")}function o(){e($(".J_menuTab.active"))}function d(){if(!$(this).hasClass("active")){var t=$(this).data("id");$(".J_mainContent .J_iframe").each(function(){return $(this).data("id")==t?($(this).show().siblings(".J_iframe").hide(),!1):void 0}),$(this).addClass("active").siblings(".J_menuTab").removeClass("active"),e(this)}}function c(){var t=$('.J_iframe[data-id="'+$(this).data("id")+'"]'),e=t.attr("src"),a=layer.load();setTimeout(function(){layer.close(a)},2000);t.attr("src",e).load(function(){layer.close(a)})}$(".J_menuItem").each(function(t){$(this).attr("data-index")||$(this).attr("data-index",t)}),$(".J_menuItem").on("click",n),$(".J_menuTabs").on("click",".J_menuTab i",s),$(".J_tabCloseOther").on("click",r),$(".J_tabShowActive").on("click",o),$(".J_menuTabs").on("click",".J_menuTab",d),$(".J_menuTabs").on("dblclick",".J_menuTab",c),$(".J_tabLeft").on("click",a),$(".J_tabRight").on("click",i),$(".J_tabCloseAll").on("click",function(){$(".page-tabs-content").children("[data-id]").not(":first").each(function(){$('.J_iframe[data-id="'+$(this).data("id")+'"]').remove(),$(this).remove()}),$(".page-tabs-content").children("[data-id]:first").each(function(){$('.J_iframe[data-id="'+$(this).data("id")+'"]').show(),$(this).addClass("active")}),$(".page-tabs-content").css("margin-left","0")})}); -------------------------------------------------------------------------------- /extend/hplusadmin/assets/js/content.min.js: -------------------------------------------------------------------------------- 1 | function $childNode(o){return window.frames[o]}function animationHover(o,e){o=$(o),o.hover(function(){o.addClass("animated "+e)},function(){window.setTimeout(function(){o.removeClass("animated "+e)},2e3)})}function WinMove(){var o="[class*=col]",e=".ibox-title",i="[class*=col]";$(o).sortable({handle:e,connectWith:i,tolerance:"pointer",forcePlaceholderSize:!0,opacity:.8}).disableSelection()}var $parentNode=window.parent.document;if($(".tooltip-demo").tooltip({selector:"[data-toggle=tooltip]",container:"body"}),$(".modal").appendTo("body"),$("[data-toggle=popover]").popover(),$(".collapse-link").click(function(){var o=$(this).closest("div.ibox"),e=$(this).find("i"),i=o.find("div.ibox-content");i.slideToggle(200),e.toggleClass("fa-chevron-up").toggleClass("fa-chevron-down"),o.toggleClass("").toggleClass("border-bottom"),setTimeout(function(){o.resize(),o.find("[id^=map-]").resize()},50)}),$(".close-link").click(function(){var o=$(this).closest("div.ibox");o.remove()}),top==this){var gohome='
';$("body").append(gohome)} -------------------------------------------------------------------------------- /extend/hplusadmin/assets/js/hplus.min.js: -------------------------------------------------------------------------------- 1 | function NavToggle(){$(".navbar-minimalize").trigger("click")}function SmoothlyMenu(){$("body").hasClass("mini-navbar")?$("body").hasClass("fixed-sidebar")?($("#side-menu").hide(),setTimeout(function(){$("#side-menu").fadeIn(500)},300)):$("#side-menu").removeAttr("style"):($("#side-menu").hide(),setTimeout(function(){$("#side-menu").fadeIn(500)},100))}function localStorageSupport(){return"localStorage"in window&&null!==window.localStorage}$(document).ready(function(){function e(){var e=$("body > #wrapper").height()-61;$(".sidebard-panel").css("min-height",e+"px")}$("#side-menu").metisMenu(),$(".right-sidebar-toggle").click(function(){$("#right-sidebar").toggleClass("sidebar-open")}),$(".sidebar-container").slimScroll({height:"100%",railOpacity:.4,wheelStep:10}),$(".open-small-chat").click(function(){$(this).children().toggleClass("fa-comments").toggleClass("fa-remove"),$(".small-chat-box").toggleClass("active")}),$(".small-chat-box .content").slimScroll({height:"234px",railOpacity:.4}),$(".check-link").click(function(){var e=$(this).find("i"),a=$(this).next("span");return e.toggleClass("fa-check-square").toggleClass("fa-square-o"),a.toggleClass("todo-completed"),!1}),$(function(){$(".sidebar-collapse").slimScroll({height:"100%",railOpacity:.9,alwaysVisible:!1})}),$(".navbar-minimalize").click(function(){$("body").toggleClass("mini-navbar"),SmoothlyMenu()}),e(),$(window).bind("load resize click scroll",function(){$("body").hasClass("body-small")||e()}),$(window).scroll(function(){$(window).scrollTop()>0&&!$("body").hasClass("fixed-nav")?$("#right-sidebar").addClass("sidebar-top"):$("#right-sidebar").removeClass("sidebar-top")}),$(".full-height-scroll").slimScroll({height:"100%"}),$("#side-menu>li").click(function(){$("body").hasClass("mini-navbar")&&NavToggle()}),$("#side-menu>li li a").click(function(){$(window).width()<769&&NavToggle()}),$(".nav-close").click(NavToggle),/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)&&$("#content-main").css("overflow-y","auto")}),$(window).bind("load resize",function(){$(this).width()<769&&($("body").addClass("mini-navbar"),$(".navbar-static-side").fadeIn())}),$(function(){if($("#fixednavbar").click(function(){$("#fixednavbar").is(":checked")?($(".navbar-static-top").removeClass("navbar-static-top").addClass("navbar-fixed-top"),$("body").removeClass("boxed-layout"),$("body").addClass("fixed-nav"),$("#boxedlayout").prop("checked",!1),localStorageSupport&&localStorage.setItem("boxedlayout","off"),localStorageSupport&&localStorage.setItem("fixednavbar","on")):($(".navbar-fixed-top").removeClass("navbar-fixed-top").addClass("navbar-static-top"),$("body").removeClass("fixed-nav"),localStorageSupport&&localStorage.setItem("fixednavbar","off"))}),$("#collapsemenu").click(function(){$("#collapsemenu").is(":checked")?($("body").addClass("mini-navbar"),SmoothlyMenu(),localStorageSupport&&localStorage.setItem("collapse_menu","on")):($("body").removeClass("mini-navbar"),SmoothlyMenu(),localStorageSupport&&localStorage.setItem("collapse_menu","off"))}),$("#boxedlayout").click(function(){$("#boxedlayout").is(":checked")?($("body").addClass("boxed-layout"),$("#fixednavbar").prop("checked",!1),$(".navbar-fixed-top").removeClass("navbar-fixed-top").addClass("navbar-static-top"),$("body").removeClass("fixed-nav"),localStorageSupport&&localStorage.setItem("fixednavbar","off"),localStorageSupport&&localStorage.setItem("boxedlayout","on")):($("body").removeClass("boxed-layout"),localStorageSupport&&localStorage.setItem("boxedlayout","off"))}),$(".s-skin-0").click(function(){return $("body").removeClass("skin-1"),$("body").removeClass("skin-2"),$("body").removeClass("skin-3"),!1}),$(".s-skin-1").click(function(){return $("body").removeClass("skin-2"),$("body").removeClass("skin-3"),$("body").addClass("skin-1"),!1}),$(".s-skin-3").click(function(){return $("body").removeClass("skin-1"),$("body").removeClass("skin-2"),$("body").addClass("skin-3"),!1}),localStorageSupport){var e=localStorage.getItem("collapse_menu"),a=localStorage.getItem("fixednavbar"),o=localStorage.getItem("boxedlayout");"on"==e&&$("#collapsemenu").prop("checked","checked"),"on"==a&&$("#fixednavbar").prop("checked","checked"),"on"==o&&$("#boxedlayout").prop("checked","checked")}if(localStorageSupport){var e=localStorage.getItem("collapse_menu"),a=localStorage.getItem("fixednavbar"),o=localStorage.getItem("boxedlayout"),l=$("body");"on"==e&&(l.hasClass("body-small")||l.addClass("mini-navbar")),"on"==a&&($(".navbar-static-top").removeClass("navbar-static-top").addClass("navbar-fixed-top"),l.addClass("fixed-nav")),"on"==o&&l.addClass("boxed-layout")}}); -------------------------------------------------------------------------------- /extend/hplusadmin/assets/js/plugins/metisMenu/jquery.metisMenu.js: -------------------------------------------------------------------------------- 1 | /* 2 | * metismenu - v1.1.3 3 | * Easy menu jQuery plugin for Twitter Bootstrap 3 4 | * https://github.com/onokumus/metisMenu 5 | * 6 | * Made by Osman Nuri Okumus 7 | * Under MIT License 8 | */ 9 | ;(function($, window, document, undefined) { 10 | 11 | var pluginName = "metisMenu", 12 | defaults = { 13 | toggle: true, 14 | doubleTapToGo: false 15 | }; 16 | 17 | function Plugin(element, options) { 18 | this.element = $(element); 19 | this.settings = $.extend({}, defaults, options); 20 | this._defaults = defaults; 21 | this._name = pluginName; 22 | this.init(); 23 | } 24 | 25 | Plugin.prototype = { 26 | init: function() { 27 | 28 | var $this = this.element, 29 | $toggle = this.settings.toggle, 30 | obj = this; 31 | 32 | if (this.isIE() <= 9) { 33 | $this.find("li.active").has("ul").children("ul").collapse("show"); 34 | $this.find("li").not(".active").has("ul").children("ul").collapse("hide"); 35 | } else { 36 | $this.find("li.active").has("ul").children("ul").addClass("collapse in"); 37 | $this.find("li").not(".active").has("ul").children("ul").addClass("collapse"); 38 | } 39 | 40 | //add the "doubleTapToGo" class to active items if needed 41 | if (obj.settings.doubleTapToGo) { 42 | $this.find("li.active").has("ul").children("a").addClass("doubleTapToGo"); 43 | } 44 | 45 | $this.find("li").has("ul").children("a").on("click" + "." + pluginName, function(e) { 46 | e.preventDefault(); 47 | 48 | //Do we need to enable the double tap 49 | if (obj.settings.doubleTapToGo) { 50 | 51 | //if we hit a second time on the link and the href is valid, navigate to that url 52 | if (obj.doubleTapToGo($(this)) && $(this).attr("href") !== "#" && $(this).attr("href") !== "") { 53 | e.stopPropagation(); 54 | document.location = $(this).attr("href"); 55 | return; 56 | } 57 | } 58 | 59 | $(this).parent("li").toggleClass("active").children("ul").collapse("toggle"); 60 | 61 | if ($toggle) { 62 | $(this).parent("li").siblings().removeClass("active").children("ul.in").collapse("hide"); 63 | } 64 | 65 | }); 66 | }, 67 | 68 | isIE: function() { //https://gist.github.com/padolsey/527683 69 | var undef, 70 | v = 3, 71 | div = document.createElement("div"), 72 | all = div.getElementsByTagName("i"); 73 | 74 | while ( 75 | div.innerHTML = "", 76 | all[0] 77 | ) { 78 | return v > 4 ? v : undef; 79 | } 80 | }, 81 | 82 | //Enable the link on the second click. 83 | doubleTapToGo: function(elem) { 84 | var $this = this.element; 85 | 86 | //if the class "doubleTapToGo" exists, remove it and return 87 | if (elem.hasClass("doubleTapToGo")) { 88 | elem.removeClass("doubleTapToGo"); 89 | return true; 90 | } 91 | 92 | //does not exists, add a new class and return false 93 | if (elem.parent().children("ul").length) { 94 | //first remove all other class 95 | $this.find(".doubleTapToGo").removeClass("doubleTapToGo"); 96 | //add the class on the current element 97 | elem.addClass("doubleTapToGo"); 98 | return false; 99 | } 100 | }, 101 | 102 | remove: function() { 103 | this.element.off("." + pluginName); 104 | this.element.removeData(pluginName); 105 | } 106 | 107 | }; 108 | 109 | $.fn[pluginName] = function(options) { 110 | this.each(function () { 111 | var el = $(this); 112 | if (el.data(pluginName)) { 113 | el.data(pluginName).remove(); 114 | } 115 | el.data(pluginName, new Plugin(this, options)); 116 | }); 117 | return this; 118 | }; 119 | 120 | })(jQuery, window, document); -------------------------------------------------------------------------------- /extend/hplusadmin/assets/js/plugins/slimscroll/jquery.slimscroll.min.js: -------------------------------------------------------------------------------- 1 | /*! Copyright (c) 2011 Piotr Rochala (http://rocha.la) 2 | * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 3 | * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. 4 | * 5 | * Version: 1.3.0 6 | * 7 | */ 8 | (function(f){jQuery.fn.extend({slimScroll:function(h){var a=f.extend({width:"auto",height:"250px",size:"4px",color:"#000",position:"right",distance:"1px",start:"top",opacity:0.4,alwaysVisible:!1,disableFadeOut:!1,railVisible:!1,railColor:"#333",railOpacity:0.2,railDraggable:!0,railClass:"slimScrollRail",barClass:"slimScrollBar",wrapperClass:"slimScrollDiv",allowPageScroll:!1,wheelStep:20,touchScrollStep:200,borderRadius:"7px",railBorderRadius:"7px"},h);this.each(function(){function r(d){if(s){d=d|| 9 | window.event;var c=0;d.wheelDelta&&(c=-d.wheelDelta/120);d.detail&&(c=d.detail/3);f(d.target||d.srcTarget||d.srcElement).closest("."+a.wrapperClass).is(b.parent())&&m(c,!0);d.preventDefault&&!k&&d.preventDefault();k||(d.returnValue=!1)}}function m(d,f,h){k=!1;var e=d,g=b.outerHeight()-c.outerHeight();f&&(e=parseInt(c.css("top"))+d*parseInt(a.wheelStep)/100*c.outerHeight(),e=Math.min(Math.max(e,0),g),e=0=b.outerHeight()?k=!0:(c.stop(!0,!0).fadeIn("fast"),a.railVisible&&g.stop(!0,!0).fadeIn("fast"))}function p(){a.alwaysVisible||(A=setTimeout(function(){a.disableFadeOut&&s||(x||y)||(c.fadeOut("slow"),g.fadeOut("slow"))},1E3))}var s,x,y,A,z,u,l,B,D=30,k=!1,b=f(this);if(b.parent().hasClass(a.wrapperClass)){var n=b.scrollTop(), 12 | c=b.parent().find("."+a.barClass),g=b.parent().find("."+a.railClass);w();if(f.isPlainObject(h)){if("height"in h&&"auto"==h.height){b.parent().css("height","auto");b.css("height","auto");var q=b.parent().parent().height();b.parent().css("height",q);b.css("height",q)}if("scrollTo"in h)n=parseInt(a.scrollTo);else if("scrollBy"in h)n+=parseInt(a.scrollBy);else if("destroy"in h){c.remove();g.remove();b.unwrap();return}m(n,!1,!0)}}else{a.height="auto"==a.height?b.parent().height():a.height;n=f("
").addClass(a.wrapperClass).css({position:"relative",width:a.width,height:a.height});b.css({width:a.width,height:a.height});var g=f("
").addClass(a.railClass).css({width:a.size,height:"100%",position:"absolute",top:0,display:a.alwaysVisible&&a.railVisible?"block":"none","border-radius":a.railBorderRadius,background:a.railColor,opacity:a.railOpacity,zIndex:90}),c=f("
").addClass(a.barClass).css({background:a.color,width:a.size,position:"absolute",top:0,opacity:a.opacity,display:a.alwaysVisible? 13 | "block":"none","border-radius":a.borderRadius,BorderRadius:a.borderRadius,MozBorderRadius:a.borderRadius,WebkitBorderRadius:a.borderRadius,zIndex:99}),q="right"==a.position?{right:a.distance}:{left:a.distance};g.css(q);c.css(q);b.wrap(n);b.parent().append(c);b.parent().append(g);a.railDraggable&&c.bind("mousedown",function(a){var b=f(document);y=!0;t=parseFloat(c.css("top"));pageY=a.pageY;b.bind("mousemove.slimscroll",function(a){currTop=t+a.pageY-pageY;c.css("top",currTop);m(0,c.position().top,!1)}); 14 | b.bind("mouseup.slimscroll",function(a){y=!1;p();b.unbind(".slimscroll")});return!1}).bind("selectstart.slimscroll",function(a){a.stopPropagation();a.preventDefault();return!1});g.hover(function(){v()},function(){p()});c.hover(function(){x=!0},function(){x=!1});b.hover(function(){s=!0;v();p()},function(){s=!1;p()});b.bind("touchstart",function(a,b){a.originalEvent.touches.length&&(z=a.originalEvent.touches[0].pageY)});b.bind("touchmove",function(b){k||b.originalEvent.preventDefault();b.originalEvent.touches.length&& 15 | (m((z-b.originalEvent.touches[0].pageY)/a.touchScrollStep,!0),z=b.originalEvent.touches[0].pageY)});w();"bottom"===a.start?(c.css({top:b.outerHeight()-c.outerHeight()}),m(0,!0)):"top"!==a.start&&(m(f(a.start).position().top,null,!0),a.alwaysVisible||c.hide());C()}});return this}});jQuery.fn.extend({slimscroll:jQuery.fn.slimScroll})})(jQuery); -------------------------------------------------------------------------------- /extend/hplusadmin/common/Resource.php: -------------------------------------------------------------------------------- 1 | getRoot() . implode(DIRECTORY_SEPARATOR, ['admin', 'view', 'index', 'index.html']); 25 | $loginView = $this->getRoot() . implode(DIRECTORY_SEPARATOR, ['admin', 'view', 'index', 'login.html']); 26 | 27 | adminModule::getInstance()->addIndexView($indexView, 'H+后台模板'); 28 | adminModule::getInstance()->addLoginView($loginView, 'H+后台模板'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /extend/myadmindata/README.md: -------------------------------------------------------------------------------- 1 | myadmin数据库 -------------------------------------------------------------------------------- /extend/myadmindata/data/uninstall.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `__PREFIX__agent_level`; 2 | 3 | DROP TABLE IF EXISTS `__PREFIX__cms_banner` ; 4 | 5 | DROP TABLE IF EXISTS `__PREFIX__cms_category` ; 6 | 7 | DROP TABLE IF EXISTS `__PREFIX__cms_content` ; 8 | 9 | DROP TABLE IF EXISTS `__PREFIX__cms_position` ; 10 | 11 | DROP TABLE IF EXISTS `__PREFIX__cms_tag` ; 12 | 13 | DROP TABLE IF EXISTS `__PREFIX__delivery_log` ; 14 | 15 | DROP TABLE IF EXISTS `__PREFIX__member`; 16 | 17 | DROP TABLE IF EXISTS `__PREFIX__member_account`; 18 | 19 | DROP TABLE IF EXISTS `__PREFIX__member_address` ; 20 | 21 | DROP TABLE IF EXISTS `__PREFIX__member_level` ; 22 | 23 | DROP TABLE IF EXISTS `__PREFIX__member_log` ; 24 | 25 | DROP TABLE IF EXISTS `__PREFIX__member_recharge` ; 26 | 27 | DROP TABLE IF EXISTS `__PREFIX__shipping_area` ; 28 | 29 | DROP TABLE IF EXISTS `__PREFIX__shipping_area_item` ; 30 | 31 | DROP TABLE IF EXISTS `__PREFIX__shipping_com`; 32 | 33 | DROP TABLE IF EXISTS `__PREFIX__shop_brand`; 34 | 35 | DROP TABLE IF EXISTS `__PREFIX__shop_cart`; 36 | 37 | DROP TABLE IF EXISTS `__PREFIX__shop_category` ; 38 | 39 | DROP TABLE IF EXISTS `__PREFIX__shop_coupon_list` ; 40 | 41 | DROP TABLE IF EXISTS `__PREFIX__shop_coupon_type` ; 42 | 43 | DROP TABLE IF EXISTS `__PREFIX__shop_goods` ; 44 | 45 | DROP TABLE IF EXISTS `__PREFIX__shop_goods_attr` ; 46 | 47 | DROP TABLE IF EXISTS `__PREFIX__shop_goods_spec` ; 48 | 49 | DROP TABLE IF EXISTS `__PREFIX__shop_goods_spec_price`; 50 | 51 | DROP TABLE IF EXISTS `__PREFIX__shop_goods_spec_value` ; 52 | 53 | DROP TABLE IF EXISTS `__PREFIX__shop_order` ; 54 | 55 | DROP TABLE IF EXISTS `__PREFIX__shop_order_action` ; 56 | 57 | DROP TABLE IF EXISTS `__PREFIX__shop_order_delivery`; 58 | 59 | DROP TABLE IF EXISTS `__PREFIX__shop_order_goods` ; 60 | 61 | DROP TABLE IF EXISTS `__PREFIX__shop_tag`; -------------------------------------------------------------------------------- /process/Monitor.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | namespace process; 16 | 17 | use Workerman\Timer; 18 | use Workerman\Worker; 19 | 20 | /** 21 | * Class FileMonitor 22 | * @package process 23 | */ 24 | class Monitor 25 | { 26 | /** 27 | * @var array 28 | */ 29 | protected $_paths = []; 30 | 31 | /** 32 | * @var array 33 | */ 34 | protected $_extensions = []; 35 | 36 | /** 37 | * FileMonitor constructor. 38 | * @param $monitor_dir 39 | * @param $monitor_extensions 40 | * @param $memory_limit 41 | */ 42 | public function __construct($monitor_dir, $monitor_extensions, $memory_limit = null) 43 | { 44 | $this->_paths = (array)$monitor_dir; 45 | $this->_extensions = $monitor_extensions; 46 | if (!Worker::getAllWorkers()) { 47 | return; 48 | } 49 | $disable_functions = explode(',', ini_get('disable_functions')); 50 | if (in_array('exec', $disable_functions, true)) { 51 | echo "\nMonitor file change turned off because exec() has been disabled by disable_functions setting in " . PHP_CONFIG_FILE_PATH . "/php.ini\n"; 52 | } else { 53 | if (!Worker::$daemonize) { 54 | Timer::add(1, function () { 55 | $this->checkAllFilesChange(); 56 | }); 57 | } 58 | } 59 | 60 | $memory_limit = $this->getMemoryLimit($memory_limit); 61 | if ($memory_limit && DIRECTORY_SEPARATOR === '/') { 62 | Timer::add(60, [$this, 'checkMemory'], [$memory_limit]); 63 | } 64 | } 65 | 66 | /** 67 | * @param $monitor_dir 68 | */ 69 | public function checkFilesChange($monitor_dir) 70 | { 71 | static $last_mtime, $too_many_files_check; 72 | if (!$last_mtime) { 73 | $last_mtime = time(); 74 | } 75 | clearstatcache(); 76 | if (!is_dir($monitor_dir)) { 77 | if (!is_file($monitor_dir)) { 78 | return; 79 | } 80 | $iterator = [new \SplFileInfo($monitor_dir)]; 81 | } else { 82 | // recursive traversal directory 83 | $dir_iterator = new \RecursiveDirectoryIterator($monitor_dir, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS); 84 | $iterator = new \RecursiveIteratorIterator($dir_iterator); 85 | } 86 | $count = 0; 87 | foreach ($iterator as $file) { 88 | $count ++; 89 | /** var SplFileInfo $file */ 90 | if (is_dir($file)) { 91 | continue; 92 | } 93 | // check mtime 94 | if ($last_mtime < $file->getMTime() && in_array($file->getExtension(), $this->_extensions, true)) { 95 | $var = 0; 96 | exec(PHP_BINARY . " -l " . $file, $out, $var); 97 | if ($var) { 98 | $last_mtime = $file->getMTime(); 99 | continue; 100 | } 101 | $last_mtime = $file->getMTime(); 102 | echo $file . " update and reload\n"; 103 | // send SIGUSR1 signal to master process for reload 104 | if (DIRECTORY_SEPARATOR === '/') { 105 | posix_kill(posix_getppid(), SIGUSR1); 106 | } else { 107 | return true; 108 | } 109 | break; 110 | } 111 | } 112 | if (!$too_many_files_check && $count > 1000) { 113 | echo "Monitor: There are too many files ($count files) in $monitor_dir which makes file monitoring very slow\n"; 114 | $too_many_files_check = 1; 115 | } 116 | } 117 | 118 | /** 119 | * @return bool 120 | */ 121 | public function checkAllFilesChange() 122 | { 123 | foreach ($this->_paths as $path) { 124 | if ($this->checkFilesChange($path)) { 125 | return true; 126 | } 127 | } 128 | return false; 129 | } 130 | 131 | /** 132 | * @param $memory_limit 133 | * @return void 134 | */ 135 | public function checkMemory($memory_limit) 136 | { 137 | $ppid = posix_getppid(); 138 | $children_file = "/proc/$ppid/task/$ppid/children"; 139 | if (!is_file($children_file) || !($children = file_get_contents($children_file))) { 140 | return; 141 | } 142 | foreach (explode(' ', $children) as $pid) { 143 | $pid = (int)$pid; 144 | $status_file = "/proc/$pid/status"; 145 | if (!is_file($status_file) || !($status = file_get_contents($status_file))) { 146 | continue; 147 | } 148 | $mem = 0; 149 | if (preg_match('/VmRSS\s*?:\s*?(\d+?)\s*?kB/', $status, $match)) { 150 | $mem = $match[1]; 151 | } 152 | $mem = (int)($mem / 1024); 153 | if ($mem >= $memory_limit) { 154 | posix_kill($pid, SIGINT); 155 | } 156 | } 157 | } 158 | 159 | /** 160 | * Get memory limit 161 | * @return float 162 | */ 163 | protected function getMemoryLimit($memory_limit) 164 | { 165 | if ($memory_limit === 0) { 166 | return 0; 167 | } 168 | $use_php_ini = false; 169 | if (!$memory_limit) { 170 | $memory_limit = ini_get('memory_limit'); 171 | $use_php_ini = true; 172 | } 173 | 174 | if ($memory_limit == -1) { 175 | return 0; 176 | } 177 | $unit = $memory_limit[strlen($memory_limit) - 1]; 178 | if ($unit == 'G') { 179 | $memory_limit = 1024 * (int)$memory_limit; 180 | } else if ($unit == 'M') { 181 | $memory_limit = (int)$memory_limit; 182 | } else if ($unit == 'K') { 183 | $memory_limit = (int)($memory_limit / 1024); 184 | } else { 185 | $memory_limit = (int)($memory_limit / (1024 * 1024)); 186 | } 187 | if ($memory_limit < 30) { 188 | $memory_limit = 30; 189 | } 190 | if ($use_php_ini) { 191 | $memory_limit = (int)(0.8 * $memory_limit); 192 | } 193 | return $memory_limit; 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 404 Not Found - webman 4 | 5 | 6 |
7 |

404 Not Found

8 |
9 |
10 |
webman
11 | 12 | 13 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-tpext/mywebman/9d49dc60d7ff7f57539810ce303f0edd736a06bc/public/favicon.ico -------------------------------------------------------------------------------- /public/linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | php ../start.php start -------------------------------------------------------------------------------- /public/windows.bat: -------------------------------------------------------------------------------- 1 | CHCP 65001 2 | php ..\windows.php 3 | pause -------------------------------------------------------------------------------- /runtime/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !logs 3 | !views 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /runtime/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /runtime/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /start.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | getOperation(); 11 | $autoload = method_exists($operation, 'getPackage') ? $operation->getPackage()->getAutoload() : $operation->getTargetPackage()->getAutoload(); 12 | if (!isset($autoload['psr-4'])) { 13 | return; 14 | } 15 | foreach ($autoload['psr-4'] as $namespace => $path) { 16 | $install_function = "\\{$namespace}Install::install"; 17 | $plugin_const = "\\{$namespace}Install::WEBMAN_PLUGIN"; 18 | if (defined($plugin_const) && is_callable($install_function)) { 19 | $install_function(); 20 | } 21 | } 22 | } 23 | 24 | public static function update($event) 25 | { 26 | static::install($event); 27 | } 28 | 29 | public static function uninstall($event) 30 | { 31 | static::findHepler(); 32 | $autoload = $event->getOperation()->getPackage()->getAutoload(); 33 | if (!isset($autoload['psr-4'])) { 34 | return; 35 | } 36 | foreach ($autoload['psr-4'] as $namespace => $path) { 37 | $uninstall_function = "\\{$namespace}Install::uninstall"; 38 | $plugin_const = "\\{$namespace}Install::WEBMAN_PLUGIN"; 39 | if (defined($plugin_const) && is_callable($uninstall_function)) { 40 | $uninstall_function(); 41 | } 42 | } 43 | } 44 | 45 | protected static function findHepler() 46 | { 47 | // Plugin.php in vendor 48 | $file = __DIR__ . '/../../../../../support/helpers.php'; 49 | if (is_file($file)) { 50 | require_once $file; 51 | return; 52 | } 53 | // Plugin.php in webman 54 | require_once __DIR__ . '/helpers.php'; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /support/Request.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | namespace support; 16 | 17 | /** 18 | * Class Request 19 | * @package support 20 | */ 21 | class Request extends \think\Request 22 | { 23 | 24 | } -------------------------------------------------------------------------------- /support/Response.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | namespace support; 16 | 17 | /** 18 | * Class Response 19 | * @package support 20 | */ 21 | class Response extends \Webman\Http\Response 22 | { 23 | 24 | } -------------------------------------------------------------------------------- /support/bootstrap.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | use Dotenv\Dotenv; 16 | use support\Log; 17 | use Webman\Bootstrap; 18 | use Webman\Config; 19 | use Webman\Middleware; 20 | use Webman\Route; 21 | use Webman\Util; 22 | 23 | $worker = $worker ?? null; 24 | 25 | set_error_handler(function ($level, $message, $file = '', $line = 0) { 26 | if (error_reporting() & $level) { 27 | throw new ErrorException($message, 0, $level, $file, $line); 28 | } 29 | }); 30 | 31 | if ($worker) { 32 | register_shutdown_function(function ($startTime) { 33 | if (time() - $startTime <= 0.1) { 34 | sleep(1); 35 | } 36 | }, time()); 37 | } 38 | 39 | if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) { 40 | if (method_exists('Dotenv\Dotenv', 'createUnsafeMutable')) { 41 | Dotenv::createUnsafeMutable(base_path())->load(); 42 | } else { 43 | Dotenv::createMutable(base_path())->load(); 44 | } 45 | } 46 | 47 | Config::clear(); 48 | support\App::loadAllConfig(['route']); 49 | if ($timezone = config('app.default_timezone')) { 50 | date_default_timezone_set($timezone); 51 | } 52 | 53 | foreach (config('autoload.files', []) as $file) { 54 | include_once $file; 55 | } 56 | foreach (config('plugin', []) as $firm => $projects) { 57 | foreach ($projects as $name => $project) { 58 | if (!is_array($project)) { 59 | continue; 60 | } 61 | foreach ($project['autoload']['files'] ?? [] as $file) { 62 | include_once $file; 63 | } 64 | } 65 | foreach ($projects['autoload']['files'] ?? [] as $file) { 66 | include_once $file; 67 | } 68 | } 69 | 70 | Middleware::load(config('middleware', [])); 71 | foreach (config('plugin', []) as $firm => $projects) { 72 | foreach ($projects as $name => $project) { 73 | if (!is_array($project) || $name === 'static') { 74 | continue; 75 | } 76 | Middleware::load($project['middleware'] ?? []); 77 | } 78 | Middleware::load($projects['middleware'] ?? [], $firm); 79 | if ($staticMiddlewares = config("plugin.$firm.static.middleware")) { 80 | Middleware::load(['__static__' => $staticMiddlewares], $firm); 81 | } 82 | } 83 | Middleware::load(['__static__' => config('static.middleware', [])]); 84 | 85 | foreach (config('bootstrap', []) as $className) { 86 | if (!class_exists($className)) { 87 | $log = "Warning: Class $className setting in config/bootstrap.php not found\r\n"; 88 | echo $log; 89 | Log::error($log); 90 | continue; 91 | } 92 | /** @var Bootstrap $className */ 93 | $className::start($worker); 94 | } 95 | 96 | foreach (config('plugin', []) as $firm => $projects) { 97 | foreach ($projects as $name => $project) { 98 | if (!is_array($project)) { 99 | continue; 100 | } 101 | foreach ($project['bootstrap'] ?? [] as $className) { 102 | if (!class_exists($className)) { 103 | $log = "Warning: Class $className setting in config/plugin/$firm/$name/bootstrap.php not found\r\n"; 104 | echo $log; 105 | Log::error($log); 106 | continue; 107 | } 108 | /** @var Bootstrap $className */ 109 | $className::start($worker); 110 | } 111 | } 112 | foreach ($projects['bootstrap'] ?? [] as $className) { 113 | /** @var string $className */ 114 | if (!class_exists($className)) { 115 | $log = "Warning: Class $className setting in plugin/$firm/config/bootstrap.php not found\r\n"; 116 | echo $log; 117 | Log::error($log); 118 | continue; 119 | } 120 | /** @var Bootstrap $className */ 121 | $className::start($worker); 122 | } 123 | } 124 | 125 | $directory = base_path() . '/plugin'; 126 | $paths = [config_path()]; 127 | foreach (Util::scanDir($directory) as $path) { 128 | if (is_dir($path = "$path/config")) { 129 | $paths[] = $path; 130 | } 131 | } 132 | Route::load($paths); 133 | 134 | -------------------------------------------------------------------------------- /windows.php: -------------------------------------------------------------------------------- 1 | load(); 18 | } else { 19 | Dotenv::createMutable(base_path())->load(); 20 | } 21 | } 22 | 23 | App::loadAllConfig(['route']); 24 | 25 | $errorReporting = config('app.error_reporting'); 26 | if (isset($errorReporting)) { 27 | error_reporting($errorReporting); 28 | } 29 | 30 | $runtimeProcessPath = runtime_path() . DIRECTORY_SEPARATOR . '/windows'; 31 | if (!is_dir($runtimeProcessPath)) { 32 | mkdir($runtimeProcessPath); 33 | } 34 | $processFiles = [ 35 | __DIR__ . DIRECTORY_SEPARATOR . 'start.php' 36 | ]; 37 | foreach (config('process', []) as $processName => $config) { 38 | $processFiles[] = write_process_file($runtimeProcessPath, $processName, ''); 39 | } 40 | 41 | foreach (config('plugin', []) as $firm => $projects) { 42 | foreach ($projects as $name => $project) { 43 | if (!is_array($project)) { 44 | continue; 45 | } 46 | foreach ($project['process'] ?? [] as $processName => $config) { 47 | $processFiles[] = write_process_file($runtimeProcessPath, $processName, "$firm.$name"); 48 | } 49 | } 50 | foreach ($projects['process'] ?? [] as $processName => $config) { 51 | $processFiles[] = write_process_file($runtimeProcessPath, $processName, $firm); 52 | } 53 | } 54 | 55 | function write_process_file($runtimeProcessPath, $processName, $firm): string 56 | { 57 | $processParam = $firm ? "plugin.$firm.$processName" : $processName; 58 | $configParam = $firm ? "config('plugin.$firm.process')['$processName']" : "config('process')['$processName']"; 59 | $fileContent = << true]); 99 | if (!$resource) { 100 | exit("Can not execute $cmd\r\n"); 101 | } 102 | return $resource; 103 | } 104 | 105 | $resource = popen_processes($processFiles); 106 | echo "\r\n"; 107 | while (1) { 108 | sleep(1); 109 | if (!empty($monitor) && $monitor->checkAllFilesChange()) { 110 | $status = proc_get_status($resource); 111 | $pid = $status['pid']; 112 | shell_exec("taskkill /F /T /PID $pid"); 113 | proc_close($resource); 114 | $resource = popen_processes($processFiles); 115 | } 116 | } 117 | --------------------------------------------------------------------------------