简介:Jshop小程序商城源代码是一套面向中小企业及开发者的一站式移动电商解决方案,支持微信小程序、支付宝小程序、APP、公众号与H5多端统一管理,适用于快速搭建自有品牌线上商城或二次开发定制化电商系统。资源包为RAR格式,大小108.18MB,包含后台ThinkPHP5.1框架核心代码、小程序前端源码、API接口层及基础数据库结构,文件类型涵盖PHP后端逻辑、WXML/WXSS/JS小程序页面组件、SQL初始化脚本等,结构清晰、模块解耦,便于理解全栈电商架构与DIY可视化功能实现原理。已有249人学习下载,适合具备PHP和小程序基础的中阶开发者深入研读源码、复用业务模块、调试多端适配逻辑,或基于其低门槛特性开展教学演示与项目实训。
1. 这不是又一个“套模板改logo”的小程序商城:Jshop 的 DIY 可视化编辑器真能拖拽出首页,且后端 PHP 模块全开源可改
上周帮某高校实验室搭一个校园二手书流转小程序,原计划用现成 SaaS 工具——结果发现所有标榜“可视化装修”的平台,前端页面能拖拽,但一进后台就卡死:轮播图 Banner 配置项藏在三级菜单里,商品分类排序要手写 JSON,更别说想加个“按学院筛选”的自定义字段。最后翻到 Jshop 小程序商城源码包,解压打开admin/目录下那个叫diy-editor的文件夹,直接把pages/index/index.json拖进编辑器,三分钟加了个带学院下拉的搜索栏组件,保存后小程序真就实时渲染出来了。这不是演示视频,是我在本地php -S起的服务上亲眼看到的。它用 PHP(非 Node.js 或 Java)做核心业务层,微信小程序端完全独立,前后端彻底分离;所有 DIY 页面结构、组件数据、样式配置都存 MySQL,不依赖任何闭源云服务。适合需要深度定制商品流、营销规则、权限体系的中小团队——你得愿意碰 PHP 代码,但不用从零写支付对接。
2. 技术栈与工程结构:PHP 8.1 + ThinkPHP 6.1 为基座,小程序端走标准 WXML/WXSS,DIY 编辑器是独立 Vue 3 应用
Jshop 并非“PHP 写后台 + 小程序套壳”那种松散组合。它的三层结构非常清晰:后端 API 层(ThinkPHP 6.1)、管理后台(Vue 2 + Element UI)、DIY 可视化编辑器(Vue 3 + TypeScript + Vite)。这种分法让每个模块职责单一,也意味着你改首页装修逻辑,不会误伤订单状态机。
2.1 后端核心:ThinkPHP 6.1 构建的 RESTful API 服务
项目根目录下的app/是业务主干。app/api/controller/下全是控制器,比如GoodsController.php处理商品列表、详情、搜索;OrderController.php管订单创建、支付回调、发货。所有接口统一返回json,无 HTML 渲染,符合小程序调用习惯。关键点在于:所有数据库操作都封装在app/common/model/对应的 Model 类中,例如app/common/model/Goods.php定义了商品表字段、关联分类、SKU 规格等,而不是在 Controller 里拼 SQL。这让你加一个“是否校内认证商品”字段时,只需在Goods.php的$schema数组里加'is_campus_verified' => 'tinyint',再在迁移文件里补上字段,Controller 和小程序端都不用动。
// app/common/model/Goods.php 片段 protected $schema = [ 'id' => 'bigint', 'title' => 'varchar', 'price' => 'decimal', 'is_campus_verified' => 'tinyint', // ← 新增字段,类型明确 'created_time' => 'datetime', ];提示:ThinkPHP 6.1 的模型自动验证和事件钩子(如
afterInsert)在这里被大量使用。比如商品上架时自动触发库存同步、生成静态 SKU 列表,逻辑都写在 Model 的event方法里,而非散落在 Controller 中。
2.2 DIY 可视化编辑器:一个跑在浏览器里的“页面组装工厂”
真正让 Jshop 区别于其他 PHP 商城的,是public/static/admin/diy-editor/这个目录。它不是一个嵌入 iframe 的简单配置页,而是一个完整的 Vue 3 单页应用(SPA),通过vite build打包后部署在管理后台的/diy路由下。编辑器本身不处理业务逻辑,只负责三件事:
- 加载当前页面的 JSON 结构(如
pages/index/index.json); - 提供组件面板(轮播、商品列表、富文本、自定义表单等),拖拽后生成带
component_id和props的节点树; - 将修改后的 JSON 结构 POST 到
/api/diy/save接口,由后端存入jshop_diy_page表。
这个设计的关键在于:JSON 结构是纯声明式描述,不包含任何 PHP 逻辑或 JS 函数体。例如一个商品列表组件的 JSON 片段长这样:
{ "id": "comp_001", "type": "goods-list", "props": { "title": "校内热卖", "category_id": 5, "limit": 8, "show_price": true, "show_sales": false }, "style": { "padding": "10px 0", "background": "#fff" } }小程序端拿到这个 JSON 后,用wx:for动态渲染对应组件——这意味着你新增一个“学院公告”组件,只需在小程序端写好components/college-notice/index.wxml,后端api/diy/render接口返回 JSON 时带上"type": "college-notice",编辑器就能识别并拖拽使用。组件能力边界由小程序端实现,编辑器只管组装。
2.3 小程序端:WXML 驱动,JSON 配置驱动,无硬编码页面
小程序代码放在miniprogram/目录,结构标准:pages/下是各页面,components/下是可复用组件,utils/是工具函数。重点看pages/index/index.js:它不写任何商品列表渲染逻辑,而是调用getDiyPageData()从后端拉取pages/index/index.json,然后遍历components数组,用this.selectComponent动态加载对应组件实例。
// miniprogram/pages/index/index.js 片段 onLoad() { this.getDiyPageData('index').then(res => { this.setData({ diyComponents: res.data.components }); }); }, // WXML 中对应 <block wx:for="{{diyComponents}}" wx:key="id"> <component is="{{'components/' + item.type + '/index'}}" >mysql -u root -p -e "CREATE DATABASE jshop CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"然后导入database/jshop.sql。注意:该 SQL 文件包含 37 张表,其中jshop_diy_page(存储 DIY 页面 JSON)、jshop_goods(商品主表)、jshop_user(用户表)是核心。导入后检查jshop_config表,确认site_url值为http://localhost:8000(这是后续小程序请求后端的域名)。
提示:SQL 文件末尾有
INSERT INTO jshop_admin (username, password, ...)初始化管理员账号,密码是明文123456,首次登录后务必在后台修改。
3.2 步骤二:配置 Nginx 虚拟主机(关键!路径别写错)
Jshop 的入口文件是public/index.php,不是根目录下的index.php。Nginx 配置必须指向public/子目录,并开启 PATH_INFO 支持(ThinkPHP 6.1 路由依赖它)。以下是我的jshop.conf:
server { listen 8000; server_name localhost; root /path/to/jshop/public; # ← 必须是 public 目录,不是项目根目录 index index.php; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; # PHP-FPM 地址 fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; include fastcgi_params; } }配置完 reload Nginx,访问http://localhost:8000应显示 ThinkPHP 默认欢迎页,证明 PHP 环境通了。
3.3 步骤三:启动管理后台与 DIY 编辑器
管理后台地址是http://localhost:8000/admin,默认账号admin/123456。登录后点击左侧菜单「DIY 可视化装修」→「首页」,即可进入编辑器。此时浏览器控制台若报Failed to fetch,大概率是跨域问题——因为编辑器是 Vue SPA,运行在http://localhost:3000(Vite 开发服务器),而后端 API 在http://localhost:8000。解决方法:在public/static/admin/diy-editor/vite.config.ts中配置代理:
// vite.config.ts export default defineConfig({ server: { proxy: { '/api': { target: 'http://localhost:8000', // ← 指向你的 Nginx changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } } })然后在diy-editor/目录下执行npm run dev,编辑器就会从http://localhost:3000启动,并将/api/diy/*请求代理到http://localhost:8000。
3.4 步骤四:小程序端真机调试(非模拟器)
小程序代码在miniprogram/,用微信开发者工具打开该目录。关键配置在project.config.json中的setting→urlCheck设为false(关闭合法域名校验),并在app.js的App()全局对象里确认apiBase指向http://localhost:8000/api。
注意:iOS 真机调试时,手机和电脑必须在同一局域网,且
apiBase要改成电脑局域网 IP(如http://192.168.1.100:8000/api),不能用localhost。安卓真机则可直接用localhost(开发者工具已做端口映射)。
4. 避坑指南:五个血泪经验总结,专治“明明按文档做了却跑不通”
这类 PHP 小程序商城最常翻车的地方,往往藏在环境细节和配置耦合里。以下是我在三台不同配置的开发机上反复验证过的典型问题,按出现频率排序。
4.1 现象:Nginx 访问http://localhost:8000/admin返回 404,但http://localhost:8000能显示 ThinkPHP 欢迎页
原因:Nginx 的root指向了项目根目录,而非public/子目录。ThinkPHP 6.1 的入口文件index.php必须在 Web 根目录下,否则路由无法解析/admin这样的 PATH_INFO。
解决:严格检查 Nginx 配置中的root指令,确保其值为/your/path/to/jshop/public,不是/your/path/to/jshop。可通过ls /your/path/to/jshop/public/index.php确认文件存在。
4.2 现象:DIY 编辑器里拖拽组件后点“保存”,控制台报401 Unauthorized
原因:编辑器前端未携带管理员登录态。Jshop 的/api/diy/*接口受AuthMiddleware中间件保护,要求请求头带Authorization: Bearer {token},而 Vite 开发服务器默认不转发 Cookie。
解决:在diy-editor/src/utils/request.ts的 axios 实例中,显式开启withCredentials: true:
// diy-editor/src/utils/request.ts const service = axios.create({ baseURL: '/api', timeout: 10000, withCredentials: true // ← 关键!让浏览器自动带上 Cookie });同时确保 Nginx 的Access-Control-Allow-Credentials响应头为true(已在jshop.conf的location ~ \.php$块中配置)。
4.3 现象:小程序端首页空白,控制台报Cannot find module 'components/goods-list/index'
原因:miniprogram/app.json中的usingComponents未注册该组件,或组件路径大小写错误(Windows 不敏感,Linux 敏感)。Jshop 的组件路径约定是全小写加短横线,如goods-list,而非GoodsList。
解决:打开miniprogram/app.json,检查usingComponents是否包含:
"usingComponents": { "goods-list": "/components/goods-list/index" }并确认miniprogram/components/goods-list/index.wxml文件真实存在,且文件名是小写。
4.4 现象:商品图片上传后,管理后台显示正常,但小程序端图片 404
原因:图片存储路径配置不一致。Jshop 默认将图片存到public/uploads/,但小程序请求时拼的是http://localhost:8000/uploads/xxx.jpg,而 Nginx 未对该路径做静态文件服务配置。
解决:在jshop.conf的server块中添加:
location ^~ /uploads/ { alias /path/to/jshop/public/uploads/; expires 30d; }注意alias末尾的/必须有,且路径要绝对。
4.5 现象:微信支付回调失败,日志显示signature verification failed
原因:config/wechat.php中的key(API 密钥)与微信商户平台设置的不一致,或mch_id(商户号)填错。Jshop 使用的是微信官方 v2 版签名算法,对参数顺序、空格、换行极其敏感。
解决:登录微信商户平台 → 「账户中心」→ 「API安全」→ 复制「API密钥」,粘贴到config/wechat.php的'key' => 'your_32_char_key_here'。切勿手动输入,用复制粘贴。同时确认mch_id是 10 位纯数字,无空格。
5. 核心模块拆解:从 DIY 页面 JSON 到小程序真实渲染的完整链路,含可复用的组件扩展模板
理解 Jshop 的核心,不在于看懂全部 37 张表,而在于搞清“一个 DIY 页面如何从 JSON 变成用户看到的首页”。这条链路横跨后端、编辑器、小程序三方,我把它拆成四个关键环节,并给出可直接复用的组件扩展代码。
5.1 环节一:后端DiyController.php如何读取并校验 JSON
当小程序请求GET /api/diy/page?name=index时,app/api/controller/DiyController.php的page()方法被调用。它不做任何渲染,只做三件事:查库、校验、返回。
// app/api/controller/DiyController.php public function page() { $name = $this->request->param('name', 'index'); // 1. 从 jshop_diy_page 表查出对应 JSON 字符串 $page = Db::name('diy_page')->where('name', $name)->find(); if (!$page) { return json(['code' => 404, 'msg' => '页面不存在']); } // 2. JSON 解析并校验结构(防注入) $data = json_decode($page['content'], true); if (json_last_error() !== JSON_ERROR_NONE || !isset($data['components'])) { return json(['code' => 500, 'msg' => '页面内容格式错误']); } // 3. 返回标准化结构,含版本号便于前端缓存 return json([ 'code' => 200, 'data' => [ 'version' => $page['updated_time'], 'components' => $data['components'] ] ]); }注意:
$page['content']是原始 JSON 字符串,json_decode后得到 PHP 数组。这里没有做任何组件逻辑处理,纯粹是“管道工”角色——确保数据安全、结构正确、快速吐出。
5.2 环节二:DIY 编辑器如何动态注册新组件
假设你要加一个“校内活动倒计时”组件。编辑器端需两步:
- 在
diy-editor/src/components/下新建Countdown.vue,定义 props(如endTime、title); - 在
diy-editor/src/config/components.ts中注册它:
// diy-editor/src/config/components.ts export const COMPONENTS = [ { id: 'countdown', name: '校内活动倒计时', icon: 'icon-time', category: '营销', props: [ { key: 'title', label: '标题', type: 'string', default: '活动即将开始' }, { key: 'endTime', label: '结束时间', type: 'datetime', default: '' } ] }, // ... 其他组件 ]注册后,编辑器左侧组件面板就会出现该组件,拖拽即生成带type: "countdown"的 JSON 节点。
5.3 环节三:小程序端如何动态加载并传递 props
这是最精妙的一环。小程序不预编译所有组件,而是运行时根据 JSON 的type字段决定加载哪个。miniprogram/components/下需新建countdown/目录,结构如下:
countdown/ ├── index.wxml ← 模板,用 {{props.title}} 绑定 ├── index.wxss ← 样式 ├── index.js ← 逻辑,接收 props 并计算倒计时 └── index.json ← 声明 component关键在index.js的properties定义:
// miniprogram/components/countdown/index.js Component({ properties: { props: { type: Object, value: {} } }, data: { timeLeft: '00:00:00' }, lifetimes: { attached() { this.countdownTimer = setInterval(() => { const now = Date.now(); const end = new Date(this.data.props.endTime).getTime(); const diff = Math.max(0, end - now); this.setData({ timeLeft: this.formatTime(diff) }); }, 1000); } }, methods: { formatTime(ms) { const d = Math.floor(ms / (1000 * 60 * 60 * 24)); const h = Math.floor((ms % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const m = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60)); const s = Math.floor((ms % (1000 * 60)) / 1000); return `${h.toString().padStart(2,'0')}:${m.toString().padStart(2,'0')}:${s.toString().padStart(2,'0')}`; } } })WXML 中直接用{{props.title}}和{{timeLeft}},无需任何额外绑定——因为properties已声明props为 Object 类型,小程序框架自动完成数据映射。
5.4 环节四:后端如何为新组件提供专属 API(以“学院筛选”为例)
如果“校内活动倒计时”只需前端逻辑,那“学院筛选”就需要后端支撑。比如你想在商品列表组件里加一个学院下拉,后端需提供学院列表接口:
// app/api/controller/CollegeController.php <?php namespace app\api\controller; use think\Controller; class CollegeController extends Controller { public function list() { // 直接查 jshop_college 表(需提前建好) $colleges = db('college')->field('id,name')->select(); return json(['code' => 200, 'data' => $colleges]); } }然后在小程序components/goods-list/index.js的onLoad里调用wx.request({ url: '/api/college/list' }),拿到学院列表后渲染下拉框。所有业务扩展,都遵循这个模式:前端提需求 → 后端加 Controller → 小程序调用 → DIY 编辑器暴露配置项。
从那以后我每次接到“加个新功能”的需求,第一反应不是翻文档,而是打开app/api/controller/新建一个 Controller 文件,写好接口,再顺藤摸瓜去改小程序组件和编辑器配置。这套 PHP + JSON + 小程序的三角闭环,比任何 SaaS 平台都透明、可控。希望帮到你。
本文还有配套的精品资源,点击获取