1 Star 0 Fork 14

iceMan / sc

forked from 铅笔刀 / sc 
Create your Gitee Account
Explore and code with more than 12 million developers,Free private repositories !:)
Sign up
This repository doesn't specify license. Please pay attention to the specific project description and its upstream code dependency when using it.
Clone or Download
contribute
Sync branch
Cancel
Notice: Creating folder will generate an empty file .keep, because not support in Git
yii
Loading...
README

[TOC]

禾匠商城v4

##前置条件

###开发者需要掌握的

  • Linux基本命令使用、文件、进程管理、Nginx+PHP+MySQL+Redis环境配置

  • PHP开发

  • MySQL数据库

  • Redis数据库

  • Yii框架

  • Vue

  • Element-UI

  • Composer

运行环境

Linux+Nginx+PHP7.2+MySQL(5.6|5.7)+Redis(4|5)

安装教程

Git版本

  1. clone https://gitee.com/zjhj/zjhj_mall_v4.git
  2. cd zjhj_mall_v4
  3. cp config/db.example.php config db.php,并配置相关数据库信息
  4. cd web(可选)
  5. php -S localhost:8000(可选)
  6. 打开浏览器访问http://localhost:8000(可选)

源代码包(开源版)

  1. 解压源代码到web目录,如/www/wwwroot/zjhj_bd/
  2. 浏览器访问您的站点,自动进入安装界面,填写数据库配置信息完成安装

配置

数据库配置

复制db.example.phpdb.php,按相关参数配置。

本地化配置

  • 环境变量

复制.env.example.php.env按需配置相关选项。

YII_DEBUG = true的情况下,所有错误结果将由Yii框架处理,YII_DEBUG = false或未配置YII_DEBUG的情况下,所有错误结果将统一处理,HTTP不再直接返回相关错误码,错误码在ajax下返回在code字段中。

  • 系统配置

复制local.example.phplocal.php按需配置相关选项。

快速上手案例

通过案例了解框架处理流程

  1. 控制器

创建文件/controllers/mall/DemoController.php

<?php
namespace app\controllers\mall;

use app\core\response\ApiCode;

class DemoController extends MallController
{
    public function actionIndex()
    {
        if (\Yii::$app->request->isAjax) { // ajax请求返回json数据,此处返回数组将自动转换成json
            return [
                'code' => ApiCode::CODE_SUCCESS,
                'data' => [
                    'content' => 'hello!',
                ],
                'msg' => 'any msg'

            ];
        } else { // 其他请求返回界面视图
            return $this->render('index');
        }
    }
}
  1. 视图文件(界面)

创建文件/views/mall/demo/index.php

<div id="app" v-cloak>
    <div>{{content}}</div>
</div>
<script>
    new Vue({
        el: '#app',
        data() {
            return {
                content: ''
            };
        },
        created() {
            this.$request({
                params: {
                    r: 'mall/demo/index'
                }
            }).then(e => {
                this.content = e.data.data.content;
            }).catch(e => {
            });
        },
    });
</script>
  1. 通过http://网站目录/web/index.php?r=mall/demo/index即可访问到。

##代码说明

###目录说明

/condif #配置文件
/controllers #控制器
/events #事件定义类
/forms #表单处理
/handlers #事件处理
/jobs #队列任务
/models #数据库表模型
/plugins #插件
/validators #自定义验证器
/views #视图文件
/web #入口文件、资源文件

###开发调试模式

要开启开发调试模式,可在项目根目录下创建.env配置文件,写入内容

YII_DEBUG=true
YII_ENV=dev

###插件开发

插件与系统交互部分:

  • 后台 菜单、权限

  • 小程序 导航菜单、底部导航、用户中心

每个插件代码放在/plugins目录下,插件格式可参照下面的demo插件,插件代码结构:

├── Plugin.php
├── assets
│   └── css
│       └── style.css
├── controllers
│   └── IndexController.php
├── models
│   └── DemoPost.php
├── tree.txt
└── views
    └── index
        └── index.php

Plugin.php: 插件配置文件,必须,需要继承\app\plugins\Plugin。

assets: 插件静态资源文件,如css、js、图片,插件安装时将自动复制到/web/assets/plugins/插件名目录下,可使用\app\helpers\PluginHelper::getPluginBaseAssetsUrl()\app\helpers\PluginHelper::getPluginAssetsPath()获取。

controllers: 插件控制器目录。

  • 后台控制器需要继承\app\plugins\Controller

  • 小程序端控制器需要继承\app\controllers\api\ApiController

models: 插件model文件,注意插件数据表对应的model也放在此文件夹下。

views: 插件视图文件。

小程序端配置:详见\app\plugins\Plugin()->getAppConfig();

规范化

开发规范

PSR12

PHP规范要求符合PSR12的代码规范https://laravel-china.org/docs/psr/

要求每个开发者给自己的代码编辑器安装规范检查工具:

PHPStorm: https://www.jianshu.com/p/b5697eb5f401

Sublime: https://blog.csdn.net/he426100/article/details/76573038

命名规范

数据表、字段、常量、变量、类、方法函数命名应该明确,尽量能从命名能知道其作用。

驼峰or下划线: 数据表、接口传递字段使用下划线,其它位置尽量使用驼峰。

数据表前缀:

核心数据表前缀使用zjhj_bd_core_,如日志、定时任务.

基础业务数据表使用zjhj_bd_xxx,如用户、商品、设置。

插件数据表使用zjhj_bd_插件_xxx。

注释规范

函数、方法应当编写对应的注释,要求写明函数说明、传入参数类型、返回参数类型。

可参考内容[https://www.cnblogs.com/hellohell/p/5733712.html]

错误处理

客户提交数据验证错误: 返回错误信息。

系统错误:抛出异常。

抛出异常将通过日志系统记录进日志。

数据库规范

  • 明确字段是否是NOT NULL的,如果是NOT NULL,就不用设置默认值了,除非真的需要,如果是可以为NULL,请设置成NOT NULL并添加默认值。

  • 表、字段 Charset 统一 utf8mb4,Collation 统一 utf8mb4_general_ci,存储引擎统一 InnoDB

  • 除非情况特殊,严禁使用 TEXT / LONGTEXT / BLOB / LONGBLOB 等类型。

  • 每张表必须加入 created_at(创建时间) / updated_at(更新时间) 字段, deleted_at(软删除时间) 字段可按需添加。 字段类型统一为TIMESTAMP, is_delete(是否删除,TINYINT(1)类型),

  • 类似 is_delete store_id 等常用查询的字段,且必须建 Index 索引。

  • 对于存储 URL 的字段,必须采用 VARCHAR 类型,建议长度:2048 - 8192,参见:https://stackoverflow.com/questions/2659952/maximum-length-of-http-get-request

GIT规范

commit备注禁止出现1提交等不明其意的备注!

目前基础功能开发提交至dev分支,后期开发各个模块、插件的功能使用各自分支,要求分支命名能明其意,保持将dev分支合并到自己分支的习惯(每天至少一次)。

不提交的文件应该加入.gitignore,避免误提交。


安全

代码安全: SQL注入 | XSS | CSRF

逻辑安全: 支付

目录规范化

.
├── config                  // 配置文件
├── controllers             // 系统控制器
│   ├── admin               // 管理员(独立版管理员)
│   ├── mall                // 商城管理
│   └── api                 // 小程序接口
├── core                    // 系统文件
├── helpers                 // 公共函数、助手类
├── models                  // 系统模型
├── plugins                 // 插件
│   └── demo                // 示例插件
│       ├── assets          // 插件静态文件(css、js)
│       ├── controllers     // 插件控制器
│       ├── models          // 插件模型
│       └── views           // 插件视图
├── runtime                 // 运行临时目录
│   ├── HTML
│   ├── URI
│   ├── cache
│   ├── debug
│   ├── gii-2.0.15.1
│   └── logs
├── validators              // 公共验证器
├── vendor
├── views                   // 系统视图
│   ├── error
│   ├── layouts
│   └── site
└── web
    └── assets
        └── plugins

公共方法/助手类

公共函数放在/helpers/functions.php, 有公共方法可以补充到这里,或是在helpers下创建自己的助手类。

本地化配置

/.env

主要存储简单的环境配置,如调试模式开关,不应放敏感信息的配置。

/config/local.php

存储系统敏感配置信息,如缓存配置、session配置。

错误处理

统一由/core/ErrorHandler处理,要求区分json和html的返回结果,错误信息保存进日志。

日志系统

日志级别

Error: 系统出错无法继续运行,如抛出Exception。

Warning: 警告,系统继续运行,只是某些结果可能跟预期不符合;场景举例:订单支付模板消息通知,模板消息没法发送成功,可记录警告信息。

Info: 普通信息,不影响系统运行;场景举例:管理员操作日志,如商品删除、订单删除、订单价格修改等操作。

统一系统日志接口

api::info(); api::warning(); api::error(); api::add( ,level);

api::delete(id); api::list(page, pageSize); api::detail(id);

返回结果

JSON数据返回结果统一以下结构

{
  "code": 0,
  "msg": "操作结果。",
  "data": 1,
  "error": null
}
参数 类型 说明
code -1 integer 用户未登录
code 0 integer 成功
code 1 integer 失败
code 500 integer 系统错误
msg - string -
data - - 返回的数据
error - - -

前端开发

前端开发的成员请先熟悉ES6新特性http://es6.ruanyifeng.com/, 优先阅读:

  • 24.编程风格

  • 2.let 和 const命令

  • 7.函数的扩展-5.箭头函数

  • 14.Promise 对象

前后端数据分离, 管理后台前端使用Vue | Element-ui | Axios, 使用示例见/controllers/DemoController。

Yii扩展组件

队列服务

用于下单单线程处理、定时任务、异步任务。

详细用法见:https://github.com/yiisoft/yii2-queue/blob/master/docs/guide/usage.md#usage

队列服务启动

  • 【方法一】一次运行,关闭控制台会自动结束。

    运行代码目录/yii queue/listen 1 即可。

  • 【方法二】自动后台运行并创建检测服务。

    运行chmod +x 代码目录/queue.sh && 代码目录/queue.sh 即可。

    此脚本会在系统crontab创建任务每分钟检测服务是否运行,不运行会自动启动。

支付

支付组件封装了微信支付和余额支付的功能。

调用组件\Yii::$app->payment

组件接口

创建待支付订单

$order = new \app\core\payment\PaymentOrder([
    'title' => '商品名称(128)',
    'amount' => 100.00, //订单金额(0.01~100000000.00)
    'orderNo' => '订单号(32)',
    'notifyClass' => MyNotifyClass::class, //支付结果通知类,需继承\app\core\payment\PaymentNotify并实现notify方法
    'supportPayTypes' => [ //选填,支持的支付方式,若不填将支持所有支付方式。
        \app\core\payment\Payment::PAY_TYPE_HUODAO, // 货到付款
        \app\core\payment\Payment::PAY_TYPE_BALANCE, // 余额
        \app\core\payment\Payment::PAY_TYPE_WECHAT, // 微信支付
        \app\core\payment\Payment::PAY_TYPE_ALIPAY, // 支付宝支付
        \app\core\payment\Payment::PAY_TYPE_BAIDU, // 百度支付
        \app\core\payment\Payment::PAY_TYPE_TOUTIAO, // 抖音头条支付
    ],
]);
$id = \Yii::$app->payment->createOrder($order);

获取待支付订单id后可将id返回给小程序端,由小程序端的支付组件完成后续付款操作。

货币

目前收录了 指定用户余额、积分(添加、减少、查询、退还) 指定用户添加余额

\Yii::$app->currency->setUser(\app\models\User)->balance->add($price, $desc, $customDesc);

指定用户减少余额

\Yii::$app->currency->setUser(\app\models\User)->balance->sub($price, $desc, $customDesc);

指定用户查询余额

\Yii::$app->currency->setUser(\app\models\User)->balance->select();

指定用户退还余额

\Yii::$app->currency->setUser(\app\models\User)->balance->refund($price, $desc, $customDesc);

指定用户添加积分

\Yii::$app->currency->setUser(\app\models\User)->integral->add($integral, $desc, $customDesc);

指定用户减少积分

\Yii::$app->currency->setUser(\app\models\User)->integral->sub($integral, $desc, $customDesc);

指定用户查询可用积分

\Yii::$app->currency->setUser(\app\models\User)->integral->select();

指定用户查询总积分

\Yii::$app->currency->setUser(\app\models\User)->integral->selectTotal();

指定用户退还积分

\Yii::$app->currency->setUser(\app\models\User)->integral->refund($price, $desc, $customDesc);

指定用户添加佣金

\Yii::$app->currency->setUser(\app\models\User)->brokerage->add($price, $desc, $customDesc);

指定用户减少佣金

\Yii::$app->currency->setUser(\app\models\User)->brokerage->sub($price, $desc, $customDesc);

指定用户查询可用佣金

\Yii::$app->currency->setUser(\app\models\User)->brokerage->select();

指定用户查询总佣金

\Yii::$app->currency->setUser(\app\models\User)->brokerage->selectTotal();

指定用户退还佣金

\Yii::$app->currency->setUser(\app\models\User)->brokerage->refund($price, $desc, $customDesc);

事件

系统中一些关键步骤会触发事件,可在应用启动时挂载一些事件处理器处理相关的事件。

挂载处理器

创建处理器handlers\\MyHandler:

<?php
namespace app\handlers;


class MyHandler extends HandlerBase
{

    /**
     * 事件处理注册
     */
    public function register()
    {
        \Yii::$app->on(\app\models\User::EVENT_REGISTER, function ($event) {
            // todo 事件相应处理
        });
    }
}

挂载处理器,编辑文件handlers/HandlerRegister.php, 在getHandlers加入自己的处理器类即可:

public function getHandlers()
    {
        return [
            OrderCreatedHandler::class,
            MyHandler::class,
        ];
    }

商城事件列表

除了框架的事件外,商城运行过程也会触发事件。

用户

事件 事件类 事件说明
app\models\User::EVENT_REGISTER app\events\UserEvent 小程序新用户加入后触发
app\models\User::EVENT_LOGIN app\events\UserEvent 小程序用户登录获取access_token时触发

订单

事件 事件类 事件说明
app\models\Order::EVENT_CREATED app\events\OrderEvent 创建新订单后触发
app\models\Order::EVENT_PAYED app\events\OrderEvent 订单支付后触发
app\models\Order::EVENT_SENT app\events\OrderEvent 订单发货后触发
app\models\Order::EVENT_CONFIRMED app\events\OrderEvent 订单确认收货后触发
app\models\Order::EVENT_SALES app\events\OrderEvent 订单过售后触发
app\models\OrderRefund::EVENT_REFUND app\events\OrderRefundEvent 订单商品售后处理完成后触发

注:售后订单处理完成后需要添加售后队列

// 判断queue队列中的售后是否已经触发
    $queueId = app\models\CoreQueueData:select(app\models\Order $order->token);
    if (!\Yii::$app->queue->isDone($queueId)) {
    // 若未触发
        return ;
    } else {
    // 若已触发,则重新添加
        $id = \Yii::$app->queue->delay(0)->push(new OrderSalesJob([
            'orderId' => app\models\Order $order->id
        ]));
        CoreQueueData::add($id, $event->order->token);
    }

订单支付完成事件对外开放

商城订单支付完成事件需要执行的操作都收录在\app\handlers\orderHandler\OrderPayedHandlerClass中
插件可以通过Plugin下面的getOrderHandler方法进行重载商城订单支付完成事件
订单支付完成事件处理需要继承\app\handles\orderHandler\BaseOrderPayedHandler

前端(后台页面)

页面规范

列表

详见示例r=mall/demo/index

  1. 使用el-card组件,头部左侧标题,右侧添加按钮(或其他操作)。

  2. 列表上边搜索表单(如果有),从左到右摆列。

  3. 列表列数数据项不宜超过6列,数据项过多尽量放在同一个单元格内,用换行方式显示。

  4. 对于可预知长度的列,尽量设定合适的宽度。

  5. 列表数据加载过程请使用element-ui的loading动画。

  6. 列表底部左侧放批量操作按钮(如果有)。

  7. 列表底部右侧放分页组件。

  8. el-card组件不要显示阴影。

  9. 按钮的大小、颜色、样式请参照demo。

表单

详见示例r=mall/demo/edit

  1. 待定

####新增分页获取用法 示例: \app\models\Goods::find()->page($pagination, $limit, $page)->all(); 使用page()方法可以直接获取分页列表;其中$pagination为null|\app\core\Pagination对象

网络

公共布局文件已经定义了全局的request实例(Axios),直接调用即可。

在vue下建议使用this.$request调用

  • GET请求
this.$request({
    method: 'get', // 默认
    params: { // GET请求参数
        r: 'demo/index',
        id: 100,
    },
}).then(response => {
    // 请求成功
    // 返回的数据
    console.log(response.data);
}).catch(error => {
    // 请求出错
});
  • POST请求
this.$request({
    method: 'post', // 默认
    params: { // GET请求参数
        r: 'demo/index',
        id: 100,
    },
    data: { // POST提交内容,数据默认统一使用Qs组件转换成QueryString
        title: 'hello',
        content: 'longtext content',
    },
}).then(response => {
    // 请求成功
    // 返回的数据
    console.log(response.data);
}).catch(error => {
    // 请求出错
});

链接跳转

在Vue内可使用this.$navigate(params, newWindow)跳转网址:

<el-button @click="$navigate({r: 'demo/index'})">在当前页面打开</el-button>
<el-button @click="$navigate({r: 'demo/index'}, true)">在新页面打开</el-button>
// 在当前页面打开
this.$navigate({
    r: 'demo/index',
    id: 1,
});

// 在新页面打开
this.$navigate({
    r: 'demo/index',
    id: 1,
}, true);

其它可使用navigateTo跳转链接

navigateTo({
    r: 'demo/index',
    id: 123
});

获取浏览器地址栏参数

链接跳转js内可使用navigateTo跳转链接

getQuery('name');

公共组件

基础选择器

基础的选择器组件,用法:

<app-picker :multiple="true" :max="2" :list="[{}, {}, {}]" @change="pickerChange"></app-picker>

参数:

  • multiple: true|false, 是否可多选文件
  • max: number, 多选文件上限

事件:

  • change: 文件选择完成,点击确认,selected(list);

附件选择器

可选择图片、视频等附件,或是上传新附件,用法:

<app-attachment :multiple="true" :max="2" @selected="attachmentSelected">选择文件</app-attachment>

参数:

  • multiple: true|false, 是否可多选文件
  • max: number, 多选文件上限
  • type: string, 文件类型,支持image|video|doc, 默认image
  • simple: true|false, 简约模式,只上传图片不加载图片库,适用于独立版管理部分

事件:

  • selected: 文件选择完成,点击确认,selected(list);

图片列表

用于展示单张或多张图片,用法

<app-gallery :show-delete="true" @deleted="picDeleted" :list="[]"></app-gallery>

参数:

  • show-delete: true|false, 是否显示删除按钮

  • list: Array, 图片列表,要求格式[ {url: 'http://xxx', ...}, {url: 'http://xxx', ...} ]

  • url: String 单图图片地址,(当传入url参数时,list参数失效) 事件:

  • deleted: 点击删除操作,deleted(item, index); // item: 被删除元素, index: 被删元素位置

导航链接列表

可选择跳转链接、底部导航链接,用法:

<app-pick-link @selected="selectAdvertUrl"><el-button size="mini">选择链接</el-button></app-pick-link>

事件:

  • selected: 链接选择完成,点击确认,selected(list);

  • type single(默认)|单选, multiple|多选

图片显示

<app-image mode="" width="50px" height="50px" src="http://aaa.com/test.jpg"></app-image>

参数:

  • mode: string, 图片显示方式,支持aspectFill(默认,图片自动裁剪),scaleToFill(不裁剪,自动拉伸)。

  • width: string, 图片宽度,默认50px。

  • radius: string, 图片圆角,默认0%

  • height: string, 图片高度,默认50px。

  • src: string, 图片地址。

自动省略号文本

<app-ellipsis :line="1">文本内容</app-ellipsis>

参数:

  • line: number, 文本行数,当文本超过这一数值将自动显示为省略号。

地图展示

可搜索位置、获取经纬度,用法:

<app-map @map-submit="mapEvent"><el-button size="mini">展开地图</el-button></app-map>

事件:

  • map-submit: 坐标选择完成,点击确认,mapEvent(e);

省市区选择器

<app-district :level="3" :detail="[]" @selected="selectDistrict" :edit="[]"></app-district>

参数:

  • level: number 展示省市区的级数 3--展示省市区 2--展示省市 1--展示省
  • detail: array 所有已选择的省市区
  • edit: array 选中的省市区

事件:

  • selected: 勾选时触发selected(list)

商品编辑

<app-goods></app-goods>

参数:

  • is_info: 基本信息显示状态 0--不显示 1--显示可编辑 2--显示不可编辑
  • in_attr:规格及库存状态 0--不显示 1--显示可编辑
  • is_goods:商品设置状态: 0--不显示 1--显示可编辑
  • is_marketing:营销设置状态: 0--不显示 1--显示可编辑
  • is_detail:商品详情状态: 0--不显示 1--显示可编辑
  • is_share:分销设置状态: 0--不显示 1--显示可编辑
  • is_member:会员设置状态: 0--不显示 1--显示可编辑
  • url:表单提交地址 默认:'mall/goods/edit'
  • referrer:表单保存之后返回地址 默认:'mall/goods/index'
  • form:动态表单数据,数据结构同form表单 (如需添加额外的规格属性(积分等))form: {extra:{first:{name:'积分',value:''}}}
  • rule:动态表单验证规则,数据数据接口同form表单验证

内部方法:

  • getDetail(id) 获取指定商品ID的商品信息
  • getCats() 获取所有分类
  • getServices() 获取商品服务
  • getCards() 获取卡券列表
  • getMembers() 获取会员列表
  • getFreight() 获取会费规则
  • getShareSetting() 获取分销设置

文本编辑器

文本编辑器支持数据双向绑定(v-model)。

// 加载组件
Yii::$app->loadViewComponent('app-rich-text')
<app-rich-text v-model="content"></app-rich-text>

热区选择

// 加载组件
Yii::$app->loadViewComponent('app-hotspot')
<app-hotspot @confirm></app-hotspot>

参数:

  • multiple:Boolean 是否多选
  • pic_url:图片的链接 String
  • width:图片宽度 String
  • height:图片高度 String
  • hotspotArray:热区数组 Array
  • is_link:是否选择链接 Boolean 事件:
  • confirm 热区选择事件 参数:热区的集合

弹窗选择组件

// 加载组件
Yii::$app->loadViewComponent('app-dialog-select')
<app-dialog-select @selected></app-dialog-select>

参数:

  • url:请求链接 String
  • multiple:是否多选 Boolean
  • title: 弹框标题 事件:
  • selected 选择的数据 当multiple为false时参数为对象,当multiple为true时参数为对象数组

模板消息

发送统一调用\app\forms\common\template\TemplateSend; 参数说明:

  • $user: 模板消息接受者的\app\models\User对象||对象数组 单发模板消息时为对象,群发模板消息时为对象数组
  • $templateTpl: 需要发送的模板消息的标示,例如订单支付标示--order_pay_tpl
  • $templateId: 需要发送的模板消息ID 仅限群发这种直接获取template_id的,其他需要查询数据库的都不可传次参数
  • $page: 小程序跳转页面
  • $data: 模板消息数据

其它

mall_setting字段说明

在后台管理代码 /models/Mall.php 有具体说明

Empty file

About

Cancel

Releases

No release

Contributors

All

Activities

Load More
can not load any more
1
https://gitee.com/thatsimple/sc.git
git@gitee.com:thatsimple/sc.git
thatsimple
sc
sc
master

Search