Ver Fonte

添加生活圈

罗永浩 há 3 meses atrás
pai
commit
3906d5b5a7

+ 2 - 0
.gitignore

@@ -9,3 +9,5 @@ addons/mpapp/
 .idea/
 node_modules/
 public/uploads/*
+.cunzhi-memory/
+.windsurf/

+ 0 - 61
.windsurf/mcp.json

@@ -1,61 +0,0 @@
-{
-  "mcpServers": {
-    "windows-mcp": {
-      "command": "uv",
-      "args": [
-        "--directory",
-        "C:/Windows-MCP",
-        "run",
-        "main.py"
-      ],
-      "env": {
-        "PYTHONUNBUFFERED": "1"
-      },
-      "metadata": {
-        "description": "Windows-MCP server for local system operations",
-        "homepage": "https://github.com/CursorTouch/Windows-MCP"
-      }
-    },
-    "filesystem": {
-      "command": "C:\\Users\\Administrator\\AppData\\Roaming\\nvm\\v18.20.2\\node.exe",
-      "args": [
-        "C:\\Users\\Administrator\\AppData\\Roaming\\nvm\\v18.20.2\\node_modules\\@modelcontextprotocol\\server-filesystem\\dist\\index.js",
-        "D:\\www"
-      ]
-    },
-    "mysqlyitongchengtest": {
-      "command": "npx",
-      "args": [
-        "-y",
-        "@bytebase/dbhub",
-        "--transport",
-        "stdio",
-        "--dsn",
-        "mysql://admin:wK7p16bw5z@123.57.137.186:3306/yitongchengtest?sslmode=disable"
-      ]
-    },
-    "mysql": {
-      "command": "npx",
-      "args": [
-        "-y",
-        "@bytebase/dbhub",
-        "--transport",
-        "stdio",
-        "--dsn",
-        "mysql://nn2025112501:kB8SXpiG7pa2iXe2@47.112.222.163:63306/nn2025112501?sslmode=disable"
-      ]
-    },
-    "fetch": {
-      "command": "C:\\Users\\Administrator\\AppData\\Roaming\\nvm\\v20.19.5\\node.exe",
-      "args": [
-        "C:\\Users\\Administrator\\AppData\\Roaming\\nvm\\v20.19.5\\node_modules\\fetch-mcp\\dist\\index.js"
-      ]
-    },
-    "windows-cli": {
-      "command": "C:\\Users\\Administrator\\AppData\\Roaming\\nvm\\v20.19.5\\node.exe",
-      "args": [
-        "C:\\Users\\Administrator\\AppData\\Roaming\\nvm\\v20.19.5\\windows-cli-mcp-server-main\\dist\\index.js"
-      ]
-    }
-  }
-}

+ 181 - 13
addons/admin/src/views/orders/afterType.vue

@@ -113,31 +113,163 @@
 			</ele-data-table>
 		</el-card>
 
-		<!-- 订单详情弹窗(引用共用组件的详情部分) -->
-		<el-dialog title="售后订单详情" :visible.sync="detailVisible" width="85%" top="3vh" :close-on-click-modal="false"
+		<!-- 订单详情弹窗 -->
+		<el-dialog title="售后订单详情" :visible.sync="detailVisible" width="90%" top="3vh" :close-on-click-modal="false"
 			custom-class="order-detail-dialog">
 			<div v-loading="detailLoading" class="order-detail-content">
-				<!-- 这里可以复用订单详情的内容 -->
-				<el-alert title="售后申请信息" type="warning" :closable="false" style="margin-bottom: 20px;">
-					<div>
-						<p><strong>联系人:</strong>{{ orderInfo.after_realname }}</p>
-						<p><strong>联系电话:</strong>{{ orderInfo.after_phone }}</p>
-						<p><strong>售后原因:</strong>{{ orderInfo.after_remark }}</p>
-						<p v-if="orderInfo.refund_remark"><strong>处理备注:</strong>{{ orderInfo.refund_remark }}</p>
+				<!-- 售后申请信息 -->
+				<el-card shadow="never" style="margin-bottom: 20px;">
+					<div slot="header" style="display: flex; align-items: center; justify-content: space-between;">
+						<span style="font-weight: bold;">
+							<i class="el-icon-warning-outline"></i> 售后申请信息
+						</span>
+						<el-tag :type="orderInfo.refund_status == 3 ? 'warning' : orderInfo.refund_status == 1 ? 'success' : 'danger'" size="small">
+							{{ orderInfo.refund_status == 3 ? '待审核' : orderInfo.refund_status == 1 ? '已处理' : '已驳回' }}
+						</el-tag>
 					</div>
-				</el-alert>
+					<el-row :gutter="20">
+						<el-col :span="8">
+							<div class="info-item">
+								<span class="info-label">联系人:</span>
+								<span class="info-value">{{ orderInfo.after_realname || '-' }}</span>
+							</div>
+						</el-col>
+						<el-col :span="8">
+							<div class="info-item">
+								<span class="info-label">联系电话:</span>
+								<span class="info-value">{{ orderInfo.after_phone || '-' }}</span>
+							</div>
+						</el-col>
+						<el-col :span="8">
+							<div class="info-item">
+								<span class="info-label">申请时间:</span>
+								<span class="info-value">{{ orderInfo.create_time || '-' }}</span>
+							</div>
+						</el-col>
+					</el-row>
+					<el-row :gutter="20" style="margin-top: 15px;">
+						<el-col :span="24">
+							<div class="info-item">
+								<span class="info-label">售后原因:</span>
+								<span class="info-value">{{ orderInfo.after_remark || '-' }}</span>
+							</div>
+						</el-col>
+					</el-row>
+					<el-row :gutter="20" style="margin-top: 15px;" v-if="orderInfo.refund_remark">
+						<el-col :span="24">
+							<div class="info-item">
+								<span class="info-label">处理备注:</span>
+								<span class="info-value" style="color: #E6A23C;">{{ orderInfo.refund_remark }}</span>
+							</div>
+						</el-col>
+					</el-row>
+				</el-card>
+
+				<!-- 订单基本信息 -->
+				<el-card shadow="never" style="margin-bottom: 20px;">
+					<div slot="header" style="font-weight: bold;">
+						<i class="el-icon-document"></i> 订单基本信息
+					</div>
+					<el-row :gutter="20">
+						<el-col :span="8">
+							<div class="info-item">
+								<span class="info-label">订单号:</span>
+								<span class="info-value">{{ orderInfo.order_no || '-' }}</span>
+							</div>
+						</el-col>
+						<el-col :span="8">
+							<div class="info-item">
+								<span class="info-label">订单状态:</span>
+								<el-tag :type="getStatusType(orderInfo.status)" size="mini">
+									{{ getStatusText(orderInfo.status) }}
+								</el-tag>
+							</div>
+						</el-col>
+						<el-col :span="8">
+							<div class="info-item">
+								<span class="info-label">支付方式:</span>
+								<span class="info-value">{{ getPayTypeText(orderInfo.pay_type) }}</span>
+							</div>
+						</el-col>
+					</el-row>
+					<el-row :gutter="20" style="margin-top: 15px;">
+						<el-col :span="8">
+							<div class="info-item">
+								<span class="info-label">订单金额:</span>
+								<span class="info-value" style="color: #F56C6C; font-weight: bold;">¥{{ orderInfo.pay_total || '0.00' }}</span>
+							</div>
+						</el-col>
+						<el-col :span="8">
+							<div class="info-item">
+								<span class="info-label">下单时间:</span>
+								<span class="info-value">{{ orderInfo.create_time || '-' }}</span>
+							</div>
+						</el-col>
+						<el-col :span="8">
+							<div class="info-item">
+								<span class="info-label">支付时间:</span>
+								<span class="info-value">{{ orderInfo.pay_at || '-' }}</span>
+							</div>
+						</el-col>
+					</el-row>
+				</el-card>
+
+				<!-- 商品信息 -->
+				<el-card shadow="never" style="margin-bottom: 20px;" v-if="orderInfo.goods">
+					<div slot="header" style="font-weight: bold;">
+						<i class="el-icon-goods"></i> 商品信息
+					</div>
+					<div style="display: flex; align-items: center; padding: 10px; background: #f5f7fa; border-radius: 4px;">
+						<el-image :src="orderInfo.goods.thumb" style="width: 80px; height: 80px; margin-right: 20px; border-radius: 4px;" fit="cover" />
+						<div style="flex: 1;">
+							<div style="font-size: 16px; font-weight: bold; margin-bottom: 8px;">{{ orderInfo.goods.goods_name }}</div>
+							<div style="color: #909399; font-size: 14px;">
+								<span>规格:{{ orderInfo.goods.spec_name || '默认' }}</span>
+								<span style="margin-left: 20px;">数量:{{ orderInfo.goods_num || 1 }}</span>
+							</div>
+						</div>
+						<div style="text-align: right;">
+							<div style="color: #F56C6C; font-size: 18px; font-weight: bold;">¥{{ orderInfo.goods.price || '0.00' }}</div>
+						</div>
+					</div>
+				</el-card>
 
-				<p style="text-align: center; color: #909399;">详细订单信息请查看订单管理</p>
+				<!-- 用户信息 -->
+				<el-card shadow="never" v-if="orderInfo.user">
+					<div slot="header" style="font-weight: bold;">
+						<i class="el-icon-user"></i> 用户信息
+					</div>
+					<el-row :gutter="20">
+						<el-col :span="8">
+							<div class="info-item">
+								<span class="info-label">用户昵称:</span>
+								<span class="info-value">{{ orderInfo.user.nickname || '-' }}</span>
+							</div>
+						</el-col>
+						<el-col :span="8">
+							<div class="info-item">
+								<span class="info-label">真实姓名:</span>
+								<span class="info-value">{{ orderInfo.user.realname || '-' }}</span>
+							</div>
+						</el-col>
+						<el-col :span="8">
+							<div class="info-item">
+								<span class="info-label">联系电话:</span>
+								<span class="info-value">{{ orderInfo.user.mobile || '-' }}</span>
+							</div>
+						</el-col>
+					</el-row>
+				</el-card>
 			</div>
 			<div slot="footer">
 				<el-button @click="detailVisible = false">关闭</el-button>
 				<el-button type="success" @click="handleAgreeDetail"
 					v-if="orderInfo.refund_status == 3 && permission.includes('sys:afterType:status')">
-					同意售后
+					<i class="el-icon-check"></i> 同意售后
 				</el-button>
 				<el-button type="danger" @click="handleRejectDetail"
 					v-if="orderInfo.refund_status == 3 && permission.includes('sys:afterType:status')">
-					驳回售后
+					<i class="el-icon-close"></i> 驳回售后
 				</el-button>
 			</div>
 		</el-dialog>
@@ -256,6 +388,10 @@ export default {
 			const map = { 1: 'info', 2: 'warning', 3: 'primary', 4: 'success' };
 			return map[status] || '';
 		},
+		getPayTypeText(payType) {
+			const map = { 10: '微信支付', 20: '支付宝', 30: '余额支付' };
+			return map[payType] || '未知';
+		}
 	}
 }
 </script>
@@ -266,4 +402,36 @@ export default {
 	overflow-y: auto;
 	padding: 10px;
 }
+
+.info-item {
+	display: flex;
+	align-items: center;
+	line-height: 32px;
+}
+
+.info-label {
+	color: #909399;
+	font-size: 14px;
+	min-width: 80px;
+}
+
+.info-value {
+	color: #303133;
+	font-size: 14px;
+	flex: 1;
+}
+
+.order-detail-dialog .el-card {
+	border: 1px solid #EBEEF5;
+}
+
+.order-detail-dialog .el-card__header {
+	background: #F5F7FA;
+	padding: 15px 20px;
+	border-bottom: 1px solid #EBEEF5;
+}
+
+.order-detail-dialog .el-card__body {
+	padding: 20px;
+}
 </style>

+ 253 - 0
addons/admin/src/views/socialCircles/socialCircles.vue

@@ -0,0 +1,253 @@
+<template>
+	<div class="ele-body">
+		<el-card shadow="never">
+			<!-- 搜索表单 -->
+			<el-form :model="table.where" label-width="90px" class="ele-form-search"
+				@keyup.enter.native="$refs.table.reload()" @submit.native.prevent>
+				<el-row :gutter="15">
+					<el-col :md="8" :sm="12">
+						<el-form-item label="关键词:">
+							<el-input v-model="table.where.keyword" placeholder="请输入应用名称" clearable />
+						</el-form-item>
+					</el-col>
+					<el-col :md="6" :sm="12">
+						<el-form-item label="平台类型:">
+							<el-select v-model="table.where.link_type" placeholder="请选择" class="ele-fluid" clearable>
+								<el-option label="全部" :value="0" />
+								<el-option label="Web" :value="1" />
+								<el-option label="小程序" :value="2" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :md="6" :sm="12">
+						<el-form-item label="状态:">
+							<el-select v-model="table.where.status" placeholder="请选择" class="ele-fluid" clearable>
+								<el-option label="全部" :value="0" />
+								<el-option label="有效" :value="1" />
+								<el-option label="无效" :value="2" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :md="4" :sm="12">
+						<div class="ele-form-actions">
+							<el-button type="primary" @click="$refs.table.reload()" icon="el-icon-search"
+								class="ele-btn-icon">查询</el-button>
+							<el-button @click="handleReset()">重置</el-button>
+						</div>
+					</el-col>
+				</el-row>
+			</el-form>
+			<!-- 操作按钮 -->
+			<div class="ele-table-tool ele-table-tool-default">
+				<el-button @click="add()" type="primary" icon="el-icon-plus" class="ele-btn-icon" size="small"
+					v-if="permission.includes('sys:socialCircles:add')">添加应用</el-button>
+			</div>
+			<!-- 数据表格 -->
+			<ele-data-table ref="table" :config="table" :choose.sync="choose" height="calc(100vh - 315px)"
+				highlight-current-row>
+				<template>
+					<el-table-column type="selection" width="45" align="center" fixed="left" />
+					<el-table-column prop="id" label="ID" width="60" align="center" fixed="left" show-overflow-tooltip />
+					<el-table-column prop="logo" label="应用LOGO" width="100" align="center">
+						<template slot-scope="{row}">
+							<el-image :src="row.logo" style="width: 50px; height: 50px;" fit="cover" v-if="row.logo" />
+							<span v-else>-</span>
+						</template>
+					</el-table-column>
+					<el-table-column prop="name" label="应用名称" show-overflow-tooltip min-width="150" />
+					<el-table-column prop="link_type" label="平台类型" width="100" align="center">
+						<template slot-scope="{row}">
+							<el-tag :type="row.link_type == 1 ? 'primary' : 'success'" size="small">
+								{{ row.link_type == 1 ? 'Web' : '小程序' }}
+							</el-tag>
+						</template>
+					</el-table-column>
+					<el-table-column prop="link_url" label="链接地址" show-overflow-tooltip min-width="200" />
+					<el-table-column prop="app_id" label="AppID" show-overflow-tooltip min-width="150" />
+					<el-table-column prop="sort" label="排序" width="80" align="center" />
+					<el-table-column prop="status" label="状态" width="100" align="center">
+						<template slot-scope="{row}">
+							<el-switch v-model="row.status" @change="editStatus(row)" :active-value="1" :inactive-value="2"
+								:disabled="!permission.includes('sys:socialCircles:status')" />
+						</template>
+					</el-table-column>
+					<el-table-column prop="create_time" label="创建时间" show-overflow-tooltip min-width="160" align="center" />
+					<el-table-column label="操作" width="180px" align="center" :resizable="false" fixed="right">
+						<template slot-scope="{row}">
+							<el-link @click="edit(row)" icon="el-icon-edit" type="primary" :underline="false"
+								v-if="permission.includes('sys:socialCircles:edit')">修改</el-link>
+							<el-popconfirm title="确定要删除此应用吗?" @confirm="remove(row)" class="ele-action">
+								<el-link slot="reference" icon="el-icon-delete" type="danger" :underline="false"
+									v-if="permission.includes('sys:socialCircles:delete')">删除</el-link>
+							</el-popconfirm>
+						</template>
+					</el-table-column>
+				</template>
+			</ele-data-table>
+		</el-card>
+		<!-- 编辑弹窗 -->
+		<el-dialog :title="editForm.id ? '修改应用' : '添加应用'" :visible.sync="showEdit" width="700px" @closed="resetEditForm()"
+			:destroy-on-close="true" custom-class="ele-dialog-form" :lock-scroll="false">
+			<el-form :model="editForm" ref="editForm" :rules="editRules" label-width="100px">
+				<el-form-item label="应用名称:" prop="name">
+					<el-input v-model="editForm.name" placeholder="请输入应用名称" clearable />
+				</el-form-item>
+				<el-form-item label="应用LOGO:" prop="logo">
+					<upload-image v-model="editForm.logo" :limit="1" />
+				</el-form-item>
+				<el-form-item label="平台类型:" prop="link_type">
+					<el-radio-group v-model="editForm.link_type">
+						<el-radio :label="1">Web(需要域名授权)</el-radio>
+						<el-radio :label="2">小程序</el-radio>
+					</el-radio-group>
+				</el-form-item>
+				<el-form-item label="链接地址:" prop="link_url" v-if="editForm.link_type == 1">
+					<el-input v-model="editForm.link_url" placeholder="请输入Web链接地址" clearable />
+				</el-form-item>
+				<el-form-item label="页面地址:" prop="link_url" v-if="editForm.link_type == 2">
+					<el-input v-model="editForm.link_url" placeholder="请输入小程序页面地址" clearable />
+				</el-form-item>
+				<el-form-item label="AppID:" prop="app_id" v-if="editForm.link_type == 2">
+					<el-input v-model="editForm.app_id" placeholder="请输入小程序AppID" clearable />
+				</el-form-item>
+				<el-form-item label="排序:" prop="sort">
+					<el-input-number v-model="editForm.sort" :min="0" :max="9999" controls-position="right"
+						style="width: 100%;" />
+				</el-form-item>
+				<el-form-item label="状态:">
+					<el-radio-group v-model="editForm.status">
+						<el-radio :label="1">有效</el-radio>
+						<el-radio :label="2">无效</el-radio>
+					</el-radio-group>
+				</el-form-item>
+			</el-form>
+			<div slot="footer">
+				<el-button @click="showEdit = false">取消</el-button>
+				<el-button type="primary" @click="save">保存</el-button>
+			</div>
+		</el-dialog>
+	</div>
+</template>
+
+<script>
+import { mapGetters } from "vuex";
+import UploadImage from '@/components/uploadImage';
+
+export default {
+	name: "SocialCircles",
+	components: { UploadImage },
+	data() {
+		return {
+			table: { url: '/socialCircles/index', where: { status: 0 } },
+			choose: [],
+			showEdit: false,
+			editForm: { status: 1, link_type: 1, sort: 0 },
+			editRules: {
+				name: [
+					{ required: true, message: '请输入应用名称', trigger: 'blur' }
+				],
+				link_type: [
+					{ required: true, message: '请选择平台类型', trigger: 'change' }
+				],
+				link_url: [
+					{ required: true, message: '请输入链接地址', trigger: 'blur' }
+				],
+				app_id: [
+					{ required: true, message: '请输入AppID', trigger: 'blur' }
+				]
+			}
+		}
+	},
+	computed: {
+		...mapGetters(["permission"]),
+	},
+	methods: {
+		add() {
+			this.resetEditForm();
+			this.showEdit = true;
+		},
+		edit(row) {
+			const loading = this.$loading({ lock: true });
+			this.$http.get('/socialCircles/info', { params: { id: row.id } }).then(res => {
+				loading.close();
+				if (res.data.code === 0) {
+					this.editForm = Object.assign({}, res.data.data);
+					this.showEdit = true;
+				} else {
+					this.$message.error(res.data.msg);
+				}
+			}).catch(e => {
+				loading.close();
+				this.$message.error(e.message);
+			});
+		},
+		resetEditForm() {
+			this.editForm = { status: 1, link_type: 1, sort: 0, name: '', logo: '', link_url: '', app_id: '' };
+			if (this.$refs.editForm) {
+				this.$refs.editForm.clearValidate();
+			}
+		},
+		handleReset() {
+			this.table.where = { status: 0 };
+			this.$refs.table.reload();
+		},
+		save() {
+			this.$refs['editForm'].validate((valid) => {
+				if (valid) {
+					const loading = this.$loading({ lock: true });
+					this.$http.post('/socialCircles/edit', this.editForm).then(res => {
+						loading.close();
+						if (res.data.code === 0) {
+							this.showEdit = false;
+							this.$message({ type: 'success', message: res.data.msg });
+							this.$refs.table.reload();
+						} else {
+							this.$message.error(res.data.msg);
+						}
+					}).catch(e => {
+						loading.close();
+						this.$message.error(e.message);
+					});
+				} else {
+					return false;
+				}
+			});
+		},
+		remove(row) {
+			const loading = this.$loading({ lock: true });
+			this.$http.post('/socialCircles/delete', { id: row.id }).then(res => {
+				loading.close();
+				if (res.data.code === 0) {
+					this.$message({ type: 'success', message: res.data.msg });
+					this.$refs.table.reload();
+				} else {
+					this.$message.error(res.data.msg);
+				}
+			}).catch(e => {
+				loading.close();
+				this.$message.error(e.message);
+			});
+		},
+		editStatus(row) {
+			this.$message.closeAll()
+			const loading = this.$loading({ lock: true });
+			let params = { id: row.id, status: row.status };
+			this.$http.post('/socialCircles/status', params).then(res => {
+				loading.close();
+				if (res.data.code === 0) {
+					this.$message({ type: 'success', message: res.data.msg });
+				} else {
+					row.status = row.status == 1 ? 2 : 1;
+					this.$message.error(res.data.msg);
+				}
+			}).catch(e => {
+				loading.close();
+				row.status = row.status == 1 ? 2 : 1;
+				this.$message.error(e.message);
+			});
+		}
+	}
+}
+</script>
+
+<style scoped></style>

+ 45 - 0
app/Http/Controllers/Admin/SocialCirclesController.php

@@ -0,0 +1,45 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Http\Controllers\Admin;
+
+use App\Services\Common\SocialCirclesService;
+
+/**
+ * 生活圈推荐应用-控制器
+ * @author laravel开发员
+ * @since 2024/12/28
+ * Class SocialCirclesController
+ * @package App\Http\Controllers\Admin
+ */
+class SocialCirclesController extends Backend
+{
+    /**
+     * 构造函数
+     * @author laravel开发员
+     * @since 2024/12/28
+     * SocialCirclesController constructor.
+     */
+    public function __construct()
+    {
+        parent::__construct();
+        $this->service = new SocialCirclesService();
+    }
+
+    /**
+     * 修改状态
+     */
+    public function status()
+    {
+        $result = $this->service->status();
+        return json($result);
+    }
+}

+ 60 - 0
app/Models/SocialCirclesModel.php

@@ -0,0 +1,60 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Models;
+
+/**
+ * 生活圈推荐应用-模型
+ * @author laravel开发员
+ * @since 2024/12/28
+ * Class SocialCirclesModel
+ * @package App\Models
+ */
+class SocialCirclesModel extends BaseModel
+{
+    // 设置数据表
+    protected $table = 'social_circles';
+
+    /**
+     * 获取应用信息
+     * @param int $id
+     * @param bool $convertUrl 是否转换logo为完整URL,默认true(列表显示),false时保持相对路径(编辑使用)
+     * @return array|string
+     * @author laravel开发员
+     * @since 2024/12/28
+     */
+    public function getInfo($id, $convertUrl = true)
+    {
+        $info = parent::getInfo($id);
+        if ($info) {
+            // 处理logo:列表显示时转换为完整URL,编辑时保持相对路径
+            if (isset($info['logo'])) {
+                if ($info['logo']) {
+                    // 根据参数决定是否转换为完整URL
+                    $info['logo'] = $convertUrl ? get_image_url($info['logo']) : $info['logo'];
+                } else {
+                    $info['logo'] = '';
+                }
+            }
+            // 创建时间
+            if (isset($info['create_time']) && $info['create_time']) {
+                $info['create_time'] = datetime($info['create_time']);
+            }
+            // 更新时间
+            if (isset($info['update_time']) && $info['update_time']) {
+                $info['update_time'] = datetime($info['update_time']);
+            }
+            // 平台类型文本
+            $info['link_type_text'] = isset($info['link_type']) && $info['link_type'] == 1 ? 'Web' : '小程序';
+        }
+        return $info;
+    }
+}

+ 131 - 0
app/Services/Common/SocialCirclesService.php

@@ -0,0 +1,131 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Services\Common;
+
+use App\Models\SocialCirclesModel;
+use App\Services\BaseService;
+
+/**
+ * 生活圈推荐应用-服务类
+ * @author laravel开发员
+ * @since 2024/12/28
+ * Class SocialCirclesService
+ * @package App\Services\Common
+ */
+class SocialCirclesService extends BaseService
+{
+    /**
+     * 构造函数
+     * @author laravel开发员
+     * @since 2024/12/28
+     * SocialCirclesService constructor.
+     */
+    public function __construct()
+    {
+        $this->model = new SocialCirclesModel();
+    }
+
+    /**
+     * 添加或编辑
+     * @return array
+     * @since 2024/12/28
+     * @author laravel开发员
+     */
+    public function edit()
+    {
+        $data = request()->all();
+
+        // 图片处理:将完整URL转换为相对路径
+        if (isset($data['logo'])) {
+            if (empty($data['logo'])) {
+                // 空值保存为空字符串
+                $data['logo'] = '';
+            } else {
+                // 转换完整URL为相对路径
+                $imagePath = get_image_path($data['logo']);
+                // get_image_path返回false时也保存为空字符串
+                $data['logo'] = $imagePath !== false ? $imagePath : '';
+            }
+        } else {
+            $data['logo'] = '';
+        }
+
+        // 如果是Web类型,确保有链接地址
+        if (isset($data['link_type']) && $data['link_type'] == 1) {
+            if (empty($data['link_url'])) {
+                return message('Web类型必须填写链接地址', false);
+            }
+        }
+
+        // 如果是小程序类型,确保有app_id
+        if (isset($data['link_type']) && $data['link_type'] == 2) {
+            if (empty($data['app_id'])) {
+                return message('小程序类型必须填写AppID', false);
+            }
+        }
+
+        return parent::edit($data);
+    }
+
+    /**
+     * 获取详情信息(编辑时使用,保持logo相对路径)
+     */
+    public function info()
+    {
+        $id = request()->input("id", 0);
+        $info = [];
+        if ($id) {
+            // 传入false参数,保持logo相对路径,供上传组件使用
+            $info = $this->model->getInfo($id, true);
+        }
+        return message(MESSAGE_OK, true, $info);
+    }
+
+    /**
+     * 获取列表数据(列表显示时logo已自动转换为完整URL)
+     */
+    public function getList()
+    {
+        // 调用父类方法获取列表数据
+        // BaseService会循环调用model->getInfo(),默认参数true会自动转换logo为完整URL
+        return parent::getList();
+    }
+
+    /**
+     * 修改状态
+     */
+    public function status()
+    {
+        $params = request()->all();
+        $id = isset($params['id']) ? intval($params['id']) : 0;
+        $status = isset($params['status']) ? intval($params['status']) : 0;
+
+        if (!$id) {
+            return ['code' => 1, 'msg' => 'ID不能为空'];
+        }
+
+        if (!$status || ($status != 1 && $status != 2)) {
+            return ['code' => 1, 'msg' => '状态参数错误'];
+        }
+
+        $result = $this->model->where('id', $id)->update([
+            'status' => $status,
+            'update_time' => time()
+        ]);
+
+        if ($result !== false) {
+            return ['code' => 0, 'msg' => '状态修改成功'];
+        }
+
+        return ['code' => 1, 'msg' => '状态修改失败'];
+    }
+}

+ 10 - 0
database/lev_social_circles_menu.sql

@@ -0,0 +1,10 @@
+-- 生活圈推荐应用管理菜单
+-- 主菜单(假设父级ID为4,即系统管理)
+INSERT INTO `lev_menu` VALUES (388, 4, '生活圈应用', 'el-icon-share', '/socialCircles/index', '/socialCircles/socialCircles', '_self', '', 0, 1, '生活圈推荐应用管理', 16, 1, UNIX_TIMESTAMP(), 1, UNIX_TIMESTAMP(), 1);
+
+-- 子权限节点
+INSERT INTO `lev_menu` VALUES (389, 388, '查询应用', '', '', '', '_self', 'sys:socialCircles:index', 1, 1, '', 1, 1, UNIX_TIMESTAMP(), 1, UNIX_TIMESTAMP(), 1);
+INSERT INTO `lev_menu` VALUES (390, 388, '添加应用', '', '', '', '_self', 'sys:socialCircles:add', 1, 1, '', 5, 1, UNIX_TIMESTAMP(), 1, UNIX_TIMESTAMP(), 1);
+INSERT INTO `lev_menu` VALUES (391, 388, '修改应用', '', '', '', '_self', 'sys:socialCircles:edit', 1, 1, '', 10, 1, UNIX_TIMESTAMP(), 1, UNIX_TIMESTAMP(), 1);
+INSERT INTO `lev_menu` VALUES (392, 388, '删除应用', '', '', '', '_self', 'sys:socialCircles:delete', 1, 1, '', 15, 1, UNIX_TIMESTAMP(), 1, UNIX_TIMESTAMP(), 1);
+INSERT INTO `lev_menu` VALUES (393, 388, '设置状态', '', '', '', '_self', 'sys:socialCircles:status', 1, 1, '', 20, 1, UNIX_TIMESTAMP(), 1, UNIX_TIMESTAMP(), 1);

+ 29 - 29
resources/lang/zh-cn/api.php

@@ -43,35 +43,35 @@ return [
     '1046' => '服务器错误',
 
     // 账户
-    '2011'=>"授权登录失败,用户账号被冻结",
-    '2012'=>"授权登录失败",
-    '2013'=>"授权登录成功",
-    '2014'=>"手机号获取失败",
+    '2011' => "授权登录失败,用户账号被冻结",
+    '2012' => "授权登录失败",
+    '2013' => "授权登录成功",
+    '2014' => "手机号获取失败",
 
 
-    '2614'=> '支付用户OPENID缺少',
-    '2615'=> '支付金额错误',
-    '2616'=> '微信支付参数未配置',
-    '2617'=> '微信支付调用成功',
-    '2618'=> '微信支付调用失败',
-    '2619'=> '支付宝支付参数未配置',
-    '2620'=> '支付宝支付调用成功',
-    '2621'=> '支付宝支付调用失败',
-    '2622'=> '支付回调状态未成功',
-    '2623'=> '支付回调订单参数错误',
-    '2624'=> '支付回调付款金额错误',
-    '2625'=> '支付请求信息错误',
-    '2626'=> '订单已支付',
-    '2627'=> '订单回调支付类型不一致',
-    '2628'=> '订单付款金额错误',
-    '2629'=> '支付订单不存在',
-    '2630'=> '支付订单已处理',
-    '2631'=> '交易场景参数错误',
-    '2632'=> '支付信息处理错误',
-    '2633'=> '支付订单处理错误',
-    '2634'=> '用户账户入账错误',
-    '2635'=> '支付回调处理失败',
-    '2636'=> '订单不存在或参数错误',
-    '2637'=> '订单支付信息错误,请联系客服',
-    '2638'=> '支付回调处理成功',
+    '2614' => '支付用户OPENID缺少',
+    '2615' => '支付金额错误',
+    '2616' => '微信支付参数未配置',
+    '2617' => '微信支付调用成功',
+    '2618' => '微信支付调用失败',
+    '2619' => '支付宝支付参数未配置',
+    '2620' => '支付宝支付调用成功',
+    '2621' => '支付宝支付调用失败',
+    '2622' => '支付回调状态未成功',
+    '2623' => '支付回调订单参数错误',
+    '2624' => '支付回调付款金额错误',
+    '2625' => '支付请求信息错误',
+    '2626' => '订单已支付',
+    '2627' => '订单回调支付类型不一致',
+    '2628' => '订单付款金额错误',
+    '2629' => '支付订单不存在',
+    '2630' => '支付订单已处理',
+    '2631' => '交易场景参数错误',
+    '2632' => '支付信息处理错误',
+    '2633' => '支付订单处理错误',
+    '2634' => '用户账户入账错误',
+    '2635' => '支付回调处理失败',
+    '2636' => '订单不存在或参数错误',
+    '2637' => '订单支付信息错误,请联系客服',
+    '2638' => '支付回调处理成功',
 ];

+ 8 - 0
routes/web.php

@@ -12,6 +12,7 @@
 use App\Http\Controllers\Admin\ActionLogController;
 use App\Http\Controllers\Admin\AdController;
 use App\Http\Controllers\Admin\CityController;
+use App\Http\Controllers\Admin\SocialCirclesController;
 use App\Http\Controllers\Admin\ConfigController;
 use App\Http\Controllers\Admin\ConfigGroupController;
 use App\Http\Controllers\Admin\IndexController;
@@ -181,6 +182,13 @@ Route::post('/ad/edit', [AdController::class, 'edit']);
 Route::post('/ad/status', [AdController::class, 'status']);
 Route::post('/ad/delete', [AdController::class, 'delete']);
 
+// 生活圈推荐应用管理
+Route::get('/socialCircles/index', [SocialCirclesController::class, 'index']);
+Route::get('/socialCircles/info', [SocialCirclesController::class, 'info']);
+Route::post('/socialCircles/edit', [SocialCirclesController::class, 'edit']);
+Route::post('/socialCircles/status', [SocialCirclesController::class, 'status']);
+Route::post('/socialCircles/delete', [SocialCirclesController::class, 'delete']);
+
 // 会员管理
 Route::get('/member/index', [MemberController::class, 'index']);
 Route::get('/member/search', [MemberController::class, 'search']);