mirror of
https://gitee.com/niucloud-team/niucloud-admin.git
synced 2026-01-27 05:28:09 +00:00
update addon
This commit is contained in:
parent
5e58652a4e
commit
2f59c7d5f0
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addon\cms;
|
||||
|
||||
|
||||
/**
|
||||
* 插件安装之后单独的插件方法
|
||||
* Class Manage
|
||||
* @package addon\cms
|
||||
*/
|
||||
class Manage
|
||||
{
|
||||
/**
|
||||
* 插件安装执行
|
||||
*/
|
||||
public function install()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件卸载执行
|
||||
*/
|
||||
public function uninstall()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件升级执行
|
||||
*/
|
||||
public function upgrade()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,102 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/***************************************************** 文章表 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取文章表列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getArticleList(params: Record<string, any>) {
|
||||
return request.get(`cms/article`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章表详情
|
||||
* @param id 文章表id
|
||||
* @returns
|
||||
*/
|
||||
export function getArticleInfo(id: number) {
|
||||
return request.get(`cms/article/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加文章表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addArticle(params: Record<string, any>) {
|
||||
return request.post('cms/article', params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑文章表
|
||||
* @param params
|
||||
*/
|
||||
export function editArticle(params: Record<string, any>) {
|
||||
return request.put(`cms/article/${params.id}`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文章表
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
export function deleteArticle(id: number) {
|
||||
return request.delete(`cms/article/${id}`, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/***************************************************** 文章分类管理 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取文章分类列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getArticleCategoryList(params: Record<string, any>) {
|
||||
return request.get(`cms/category`, {params})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取文章全部分类
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getArticleCategoryAll(params: Record<string, any>) {
|
||||
return request.get(`cms/category/all`, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章分类详情
|
||||
* @param category_id
|
||||
*/
|
||||
export function getArticleCategoryInfo(category_id: number) {
|
||||
return request.get(`cms/category/${category_id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加文章分类
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function addArticleCategory(params: Record<string, any>) {
|
||||
return request.post('cms/category', params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑文章分类
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function editArticleCategory(params: Record<string, any>) {
|
||||
return request.put(`cms/category/${params.category_id}`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章分类删除
|
||||
* @param category_id
|
||||
*/
|
||||
export function deleteArticleCategory(category_id: number) {
|
||||
return request.delete(`cms/category/${category_id}`, {showSuccessMessage: true});
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "栏目名称",
|
||||
"sort": "排序",
|
||||
"isShow": "是否显示",
|
||||
"namePlaceholder": "请输入栏目名称",
|
||||
"sortPlaceholder": "请输入排序",
|
||||
"isShowPlaceholder": "是否显示",
|
||||
"addArticleCategory": "添加栏目",
|
||||
"updateArticleCategory": "编辑栏目",
|
||||
"articleCategoryDeleteTips": "确定要删除该栏目吗?",
|
||||
"nameMax": "名称不能超过20个字符",
|
||||
"sortNumber": "排序号必须是数字",
|
||||
"sortBetween": "排序号不能超过10000",
|
||||
"show": "显示",
|
||||
"hide": "不显示",
|
||||
"articleNumber": "文章数量"
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
{
|
||||
"categoryName": "文章栏目",
|
||||
"title": "文章标题",
|
||||
"intro": "简介",
|
||||
"summary": "文章摘要",
|
||||
"image": "文章图片",
|
||||
"author": "作者",
|
||||
"content": "文章内容",
|
||||
"visit": "实际浏览量",
|
||||
"visitVirtual": "初始浏览量",
|
||||
"isShow": "是否显示",
|
||||
"sort": "排序",
|
||||
"categoryIdPlaceholder": "请选择文章栏目",
|
||||
"titlePlaceholder": "请输入文章标题",
|
||||
"introPlaceholder": "请输入简介",
|
||||
"summaryPlaceholder": "请输入文章摘要",
|
||||
"imagePlaceholder": "请上传文章图片",
|
||||
"authorPlaceholder": "请输入作者",
|
||||
"contentPlaceholder": "请输入文章内容",
|
||||
"visitPlaceholder": "请输入实际浏览量",
|
||||
"visitVirtualPlaceholder": "请输入初始浏览量",
|
||||
"isShowPlaceholder": "是否显示",
|
||||
"sortPlaceholder": "请输入排序",
|
||||
"addArticle": "添加文章",
|
||||
"updateArticle": "编辑文章",
|
||||
"titleMax": "文章标题不能超过20个字符",
|
||||
"introMax": "文章简介不能超过50个字符",
|
||||
"summaryMax": "文章摘要不能超过50个字符",
|
||||
"imageMax": "图片路径太长",
|
||||
"authorMax": "文章作者不能超过20个字符",
|
||||
"isShowNumber": "是否显示必须是数字",
|
||||
"isShowBetween": "是否显示只能是0或者1",
|
||||
"sortNumber": "排序号必须是数字",
|
||||
"sortBetween": "排序号需要在0-10000之间",
|
||||
"articleNull": "未读取到文章信息!"
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
{
|
||||
"categoryName": "栏目",
|
||||
"ID": "ID",
|
||||
"title": "标题",
|
||||
"intro": "简介",
|
||||
"summary": "摘要",
|
||||
"image": "封面",
|
||||
"author": "作者",
|
||||
"content": "文章内容",
|
||||
"visit": "浏览量",
|
||||
"visitVirtual": "初始浏览量",
|
||||
"isShow": "是否显示",
|
||||
"sort": "排序",
|
||||
"createTime": "创建时间",
|
||||
"updateTime": "更新时间",
|
||||
"addArticle": "添加文章",
|
||||
"updateArticle": "编辑文章",
|
||||
"titlePlaceholder": "请输入文章标题",
|
||||
"categoryIdPlaceholder": "请选择文章栏目",
|
||||
"articleDeleteTips": "确定要删除该文章吗?"
|
||||
}
|
||||
@ -1,144 +0,0 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-[20px]">{{ pageName }}</span>
|
||||
<el-button type="primary" @click="addEvent">{{ t('addArticleCategory') }}</el-button>
|
||||
</div>
|
||||
|
||||
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="categoryTableData.searchParam" ref="searchFormRef">
|
||||
<el-form-item :label="t('name')" prop="name">
|
||||
<el-input v-model="categoryTableData.searchParam.name" :placeholder="t('namePlaceholder')" class="w-[190px]" prefix-icon="Search" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadCategoryList()">{{ t('search') }}</el-button>
|
||||
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<div class="mt-[10px]">
|
||||
<el-table :data="categoryTableData.data" size="large" v-loading="categoryTableData.loading">
|
||||
<template #empty>
|
||||
<span>{{ !categoryTableData.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
<el-table-column prop="name" :label="t('name')" min-width="150" />
|
||||
<el-table-column prop="article_num" :label="t('articleNumber')" min-width="140" />
|
||||
<el-table-column prop="is_show" :label="t('isShow')" min-width="150">
|
||||
<template #default="{ row }">
|
||||
{{ row.is_show == 1 ? t('show') : t('hide') }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="sort" :label="t('sort')" min-width="120" />
|
||||
|
||||
<el-table-column :label="t('operation')" fixed="right" width="130" align="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
||||
<el-button type="primary" link @click="deleteEvent(row.category_id)">{{ t('delete') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="categoryTableData.page" v-model:page-size="categoryTableData.limit" layout="total, sizes, prev, pager, next, jumper" :total="categoryTableData.total" @size-change="loadCategoryList()" @current-change="loadCategoryList" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<edit-category ref="editCategoryDialog" @complete="loadCategoryList()" />
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getArticleCategoryList, deleteArticleCategory } from '@/cms/api/article'
|
||||
import { ElMessageBox, FormInstance } from 'element-plus'
|
||||
import EditCategory from '@/cms/views/article/components/edit-category.vue'
|
||||
import { debounce } from '@/utils/common'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
const pageName = route.meta.title
|
||||
|
||||
const categoryTableData = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam: {
|
||||
name: ''
|
||||
}
|
||||
})
|
||||
|
||||
const searchFormRef = ref<FormInstance>()
|
||||
|
||||
const resetForm = (formEl: FormInstance | undefined)=>{
|
||||
if (!formEl) return
|
||||
formEl.resetFields();
|
||||
loadCategoryList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章分类列表
|
||||
*/
|
||||
const loadCategoryList = debounce((page: number = 1) => {
|
||||
categoryTableData.loading = true
|
||||
categoryTableData.page = page
|
||||
|
||||
getArticleCategoryList({
|
||||
page: categoryTableData.page,
|
||||
limit: categoryTableData.limit,
|
||||
...categoryTableData.searchParam
|
||||
}).then(res => {
|
||||
categoryTableData.loading = false
|
||||
categoryTableData.data = res.data.data
|
||||
categoryTableData.total = res.data.total
|
||||
}).catch(() => {
|
||||
categoryTableData.loading = false
|
||||
})
|
||||
})
|
||||
loadCategoryList()
|
||||
|
||||
const editCategoryDialog: Record<string, any> | null = ref(null)
|
||||
|
||||
/**
|
||||
* 添加文章分类
|
||||
*/
|
||||
const addEvent = () => {
|
||||
editCategoryDialog.value.setFormData()
|
||||
editCategoryDialog.value.showDialog = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑文章分类
|
||||
* @param data
|
||||
*/
|
||||
const editEvent = (data: any) => {
|
||||
editCategoryDialog.value.setFormData(data)
|
||||
editCategoryDialog.value.showDialog = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文章分类
|
||||
*/
|
||||
const deleteEvent = (id: number) => {
|
||||
ElMessageBox.confirm(t('articleCategoryDeleteTips'), t('warning'),
|
||||
{
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}
|
||||
).then(() => {
|
||||
deleteArticleCategory(id).then(() => {
|
||||
loadCategoryList()
|
||||
}).catch(() => {
|
||||
})
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -1,135 +0,0 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" :title="popTitle" width="500px" :destroy-on-close="true">
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||
<el-form-item :label="t('name')" prop="name">
|
||||
<el-input v-model="formData.name" clearable :placeholder="t('namePlaceholder')" class="input-width" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('sort')" prop="sort">
|
||||
<el-input-number v-model="formData.sort" :min="0" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('isShow')">
|
||||
<el-radio-group v-model="formData.is_show" :placeholder="t('isShowPlaceholder')">
|
||||
<el-radio :label="1">{{ t('show') }}</el-radio>
|
||||
<el-radio :label="0">{{ t('hidden') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{t('confirm')}}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { addArticleCategory, editArticleCategory, getArticleCategoryInfo } from '@/cms/api/article'
|
||||
|
||||
let popTitle: string = '';
|
||||
|
||||
let showDialog = ref(false)
|
||||
const loading = ref(true)
|
||||
|
||||
/**
|
||||
* 表单数据
|
||||
*/
|
||||
const initialFormData = {
|
||||
category_id: '',
|
||||
name: '',
|
||||
sort: '',
|
||||
is_show: 1,
|
||||
}
|
||||
const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
// 表单验证规则
|
||||
const formRules = computed(() => {
|
||||
return {
|
||||
name: [
|
||||
{ required: true, message: t('namePlaceholder'), trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
if (value.length > 20) {
|
||||
callback(new Error(t('nameMax')))
|
||||
}
|
||||
|
||||
callback()
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
sort: [
|
||||
{
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
if (value === "" || isNaN(value)) {
|
||||
callback(new Error(t('sortNumber')))
|
||||
}
|
||||
if (parseInt(value) > 10000) {
|
||||
callback(new Error(t('sortBetween')))
|
||||
}
|
||||
callback()
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['complete'])
|
||||
|
||||
/**
|
||||
* 确认
|
||||
* @param formEl
|
||||
*/
|
||||
const confirm = async (formEl: FormInstance | undefined) => {
|
||||
if (loading.value || !formEl) return
|
||||
let save = formData.category_id ? editArticleCategory : addArticleCategory
|
||||
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
loading.value = true
|
||||
|
||||
let data = formData
|
||||
|
||||
save(data).then(res => {
|
||||
loading.value = false
|
||||
showDialog.value = false
|
||||
emit('complete')
|
||||
}).catch(err => {
|
||||
loading.value = false
|
||||
// showDialog.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const setFormData = async (row: any = null) => {
|
||||
loading.value = true
|
||||
Object.assign(formData, initialFormData)
|
||||
popTitle = t('addArticleCategory');
|
||||
if (row) {
|
||||
popTitle = t('updateArticleCategory')
|
||||
const data = await (await getArticleCategoryInfo(row.category_id)).data
|
||||
Object.keys(formData).forEach((key: string) => {
|
||||
if (data[key] != undefined) formData[key] = data[key]
|
||||
})
|
||||
}
|
||||
loading.value = false
|
||||
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
showDialog,
|
||||
setFormData
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -1,176 +0,0 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<div class="detail-head">
|
||||
<div class="left" @click="router.push({ path: '/cms/article/list' })">
|
||||
<span class="iconfont iconxiangzuojiantou !text-xs"></span>
|
||||
<span class="ml-[1px]">{{t('returnToPreviousPage')}}</span>
|
||||
</div>
|
||||
<span class="adorn">|</span>
|
||||
<span class="right">{{ pageName }}</span>
|
||||
</div>
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="formData.title" clearable :placeholder="t('titlePlaceholder')" class="input-width" maxlength="20" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('categoryName')" prop="category_id">
|
||||
<el-select v-model="formData.category_id" clearable :placeholder="t('categoryIdPlaceholder')" class="input-width">
|
||||
<el-option :label="item['name']" :value="item['category_id']" v-for="item in categoryList" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('intro')" prop="intro">
|
||||
<el-input v-model="formData.intro" type="textarea" rows="4" clearable :placeholder="t('introPlaceholder')" class="input-width" maxlength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('summary')" prop="summary">
|
||||
<el-input v-model="formData.summary" type="textarea" rows="4" clearable :placeholder="t('summaryPlaceholder')" class="input-width" maxlength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('image')">
|
||||
<upload-image v-model="formData.image" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('author')" prop="author">
|
||||
<el-input v-model="formData.author" clearable :placeholder="t('authorPlaceholder')" class="input-width" maxlength="20" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('content')" prop="content">
|
||||
<editor v-model="formData.content" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('visitVirtual')">
|
||||
<el-input v-model="formData.visit_virtual" clearable :placeholder="t('visitVirtualPlaceholder')" class="input-width" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('isShow')">
|
||||
<el-radio-group v-model="formData.is_show" :placeholder="t('isShowPlaceholder')">
|
||||
<el-radio :label="1">{{ t('show') }}</el-radio>
|
||||
<el-radio :label="0">{{ t('hidden') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('sort')" prop="sort">
|
||||
<el-input-number v-model="formData.sort" :min="0" />
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="fixed-footer-wrap">
|
||||
<div class="fixed-footer">
|
||||
<el-button type="primary" @click="onSave(formRef)">{{ t('save') }}</el-button>
|
||||
<el-button @click="back()">{{ t('cancel') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { getArticleInfo, getArticleCategoryAll, addArticle, editArticle } from '@/cms/api/article'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const id: number = parseInt(route.query.id || 0)
|
||||
const loading = ref(false)
|
||||
const categoryList = ref([])
|
||||
const appStore = useAppStore()
|
||||
const pageName = route.meta.title
|
||||
|
||||
/**
|
||||
* 表单数据
|
||||
*/
|
||||
const initialFormData = {
|
||||
id: '',
|
||||
category_id: '',
|
||||
title: '',
|
||||
intro: '',
|
||||
summary: '',
|
||||
image: '',
|
||||
author: '',
|
||||
content: '',
|
||||
visit: '',
|
||||
visit_virtual: '',
|
||||
is_show: 1,
|
||||
sort: 0
|
||||
}
|
||||
|
||||
const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
|
||||
const setFormData = async (id: number = 0) => {
|
||||
loading.value = true
|
||||
Object.assign(formData, initialFormData)
|
||||
if (id) {
|
||||
const data = await (await getArticleInfo(id)).data
|
||||
if (!data || Object.keys(data).length == 0) {
|
||||
ElMessage.error(t('articleNull'))
|
||||
setTimeout(() => {
|
||||
router.go(-1)
|
||||
}, 2000)
|
||||
return false
|
||||
}
|
||||
Object.keys(formData).forEach((key: string) => {
|
||||
if (data[key] != undefined) formData[key] = data[key]
|
||||
})
|
||||
loading.value = false
|
||||
} else {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
if (id) setFormData(id)
|
||||
|
||||
const setCategoryList = async () => {
|
||||
categoryList.value = await (await getArticleCategoryAll({})).data
|
||||
// if (!id && categoryList.value.length > 0) formData.category_id = categoryList.value[0].category_id
|
||||
}
|
||||
setCategoryList()
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
// 表单验证规则
|
||||
const formRules = computed(() => {
|
||||
return {
|
||||
title: [
|
||||
{ required: true, message: t('titlePlaceholder'), trigger: 'blur' }
|
||||
],
|
||||
category_id: [
|
||||
{ required: true, message: t('categoryIdPlaceholder'), trigger: 'blur' }
|
||||
],
|
||||
content: [
|
||||
{ required: true, message: t('contentPlaceholder'), trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
const content = value.replace(/<[^<>]+>/g, '').replace(/ /gi, '')
|
||||
if (!content && value.indexOf('img') === -1) {
|
||||
callback(new Error(t('contentPlaceholder')))
|
||||
} else callback()
|
||||
},
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
const onSave = async (formEl: FormInstance | undefined) => {
|
||||
if (loading.value || !formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
loading.value = true
|
||||
const data = formData
|
||||
const save = id ? editArticle : addArticle
|
||||
save(data).then(res => {
|
||||
loading.value = false
|
||||
back()
|
||||
}).catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const back = () => {
|
||||
router.push({ path: '/cms/article/list' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -1,181 +0,0 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-[20px]">{{ pageName }}</span>
|
||||
<el-button type="primary" @click="addEvent">{{ t('addArticle') }}</el-button>
|
||||
</div>
|
||||
|
||||
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="articleTableData.searchParam" ref="searchFormRef">
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="articleTableData.searchParam.title" :placeholder="t('titlePlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('categoryName')" prop="category_id">
|
||||
<el-select v-model="articleTableData.searchParam.category_id" clearable :placeholder="t('categoryIdPlaceholder')" class="input-width">
|
||||
<el-option :label="t('selectPlaceholder')" value="" />
|
||||
<el-option :label="item['name']" :value="item['category_id']" v-for="item in categoryList" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadArticleList()">{{ t('search') }}</el-button>
|
||||
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<div class="mt-[10px]">
|
||||
<el-table :data="articleTableData.data" size="large" v-loading="articleTableData.loading">
|
||||
<template #empty>
|
||||
<span>{{ !articleTableData.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
|
||||
<el-table-column prop="id" :show-overflow-tooltip="true" :label="t('ID')" width="100" />
|
||||
|
||||
<el-table-column prop="category_name" :label="t('categoryName')" width="120" />
|
||||
|
||||
<el-table-column prop="title" :show-overflow-tooltip="true" :label="t('title')" width="180">
|
||||
<template #default="{ row }">
|
||||
<a :href="row.article_url.web_url" target="_blank">{{ row.title }}</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('image')" min-width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-image class="w-12 h-12" v-if="row.image_thumb_small" :src="img(row.image_thumb_small)" fit="contain" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="visit" :label="t('visit')" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<span>{{ parseInt(row.visit + row.visit_virtual) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('isShow')" min-width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.is_show == 1">{{ t('show') }}</span>
|
||||
<span v-if="row.is_show == 0">{{t('hidden')}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="sort" :label="t('sort')" width="100" align="center" />
|
||||
|
||||
<el-table-column :label="t('createTime')" min-width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.create_time || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('operation')" fixed="right" align="right" width="130">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
||||
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="articleTableData.page" v-model:page-size="articleTableData.limit" layout="total, sizes, prev, pager, next, jumper" :total="articleTableData.total" @size-change="loadArticleList()" @current-change="loadArticleList" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getArticleList, deleteArticle, getArticleCategoryAll } from '@/cms/api/article'
|
||||
import { img } from '@/utils/common'
|
||||
import { ElMessageBox, FormInstance } from 'element-plus'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
const route = useRoute()
|
||||
const pageName = route.meta.title
|
||||
|
||||
const articleTableData = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam: {
|
||||
title: '',
|
||||
category_id: ''
|
||||
}
|
||||
})
|
||||
const categoryList = ref([])
|
||||
|
||||
const searchFormRef = ref<FormInstance>()
|
||||
|
||||
const setCategoryList = async () => {
|
||||
categoryList.value = await (await getArticleCategoryAll({})).data
|
||||
}
|
||||
setCategoryList()
|
||||
|
||||
/**
|
||||
* 获取文章列表
|
||||
*/
|
||||
const loadArticleList = (page: number = 1) => {
|
||||
articleTableData.loading = true
|
||||
articleTableData.page = page
|
||||
|
||||
getArticleList({
|
||||
page: articleTableData.page,
|
||||
limit: articleTableData.limit,
|
||||
...articleTableData.searchParam
|
||||
}).then(res => {
|
||||
articleTableData.loading = false
|
||||
articleTableData.data = res.data.data
|
||||
articleTableData.total = res.data.total
|
||||
}).catch(() => {
|
||||
articleTableData.loading = false
|
||||
})
|
||||
}
|
||||
loadArticleList()
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
/**
|
||||
* 添加文章
|
||||
*/
|
||||
const addEvent = () => {
|
||||
router.push('/cms/article/edit')
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑文章
|
||||
* @param data
|
||||
*/
|
||||
const editEvent = (data: any) => {
|
||||
router.push(`/cms/article/edit?id=${data.id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文章
|
||||
*/
|
||||
const deleteEvent = (id: number) => {
|
||||
ElMessageBox.confirm(t('articleDeleteTips'), t('warning'),
|
||||
{
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}
|
||||
).then(() => {
|
||||
deleteArticle(id).then(() => {
|
||||
loadArticleList()
|
||||
}).catch(() => {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const resetForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.resetFields()
|
||||
loadArticleList()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -1,177 +0,0 @@
|
||||
<template>
|
||||
<!-- 内容 -->
|
||||
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('articleData') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('dataSources')">
|
||||
<el-radio-group v-model="diyStore.editComponent.sources">
|
||||
<el-radio :label="'initial'">{{t('defaultSources')}}</el-radio>
|
||||
<el-radio :label="'diy'">{{t('manualSelectionSources')}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('articleNum')" v-show="diyStore.editComponent.sources == 'initial'">
|
||||
<el-slider v-model="diyStore.editComponent.count" show-input size="small" class="ml-[10px] article-slider" :min="1" :max="30"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('manualSelectionSources')" v-show="diyStore.editComponent.sources == 'diy'" class=" flex">
|
||||
<span @click="showArticle" class="cursor-pointer flex-1" :class="{ 'text-primary' : diyStore.editComponent.articleIds.length > 0 }">{{ diyStore.editComponent.articleIds.length > 0 ? t('selected') + diyStore.editComponent.articleIds.length + t('piece') : t('selectPlaceholder') }}</span>
|
||||
<el-icon>
|
||||
<ArrowRight/>
|
||||
</el-icon>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="showDialog" :title="t('selectArticleTips')" width="60%" :close-on-press-escape="false" :close-on-click-modal="false">
|
||||
|
||||
<div>
|
||||
<el-table :data="articleTableData.data" size="large" v-loading="articleTableData.loading" @selection-change="handleSelectionChange">
|
||||
<template #empty>
|
||||
<span>{{ !articleTableData.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
|
||||
<el-table-column type="selection" width="55"/>
|
||||
|
||||
<el-table-column prop="title" :show-overflow-tooltip="true" :label="t('articleTitle')" width="140"/>
|
||||
|
||||
<el-table-column :label="t('articleImage')" min-width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-image class="w-12 h-12" v-if="row.image" :src="img(row.image)" fit="contain"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="category_name" :label="t('articleCategoryName')" align="center" min-width="140"/>
|
||||
|
||||
<el-table-column prop="summary" :label="t('articleSummary')" width="180" :show-overflow-tooltip="true"/>
|
||||
|
||||
<el-table-column :label="t('createTime')" min-width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.create_time || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="articleTableData.page" v-model:page-size="articleTableData.limit" layout="total, sizes, prev, pager, next, jumper" :total="articleTableData.total" @size-change="loadArticleList()" @current-change="loadArticleList"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="showDialog = false">{{ t('cancel')}}</el-button>
|
||||
<el-button type="primary" @click="save">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<!-- 样式 -->
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('articleStyle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('articleBgColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.elementBgColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('topRounded')">
|
||||
<el-slider v-model="diyStore.editComponent.topElementRounded" show-input size="small" class="ml-[10px] graphic-nav-slider" :max="50"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('bottomRounded')">
|
||||
<el-slider v-model="diyStore.editComponent.bottomElementRounded" show-input size="small" class="ml-[10px] graphic-nav-slider" :max="50"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 组件样式 -->
|
||||
<slot name="style"></slot>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {t} from '@/lang'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
import {ref, reactive} from 'vue'
|
||||
import {img} from '@/utils/common'
|
||||
import {getArticleList} from '@/cms/api/article'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = []; // 忽略公共属性
|
||||
|
||||
// 组件验证
|
||||
diyStore.editComponent.verify = (index: number) => {
|
||||
var res = {code: true, message: ''};
|
||||
if (diyStore.value[index].sources === 'diy' && diyStore.value[index].articleIds.length === 0) {
|
||||
res.code = false;
|
||||
res.message = t('selectArticleTip');
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
const showDialog = ref(false)
|
||||
|
||||
const showArticle = () => {
|
||||
showDialog.value = true
|
||||
}
|
||||
|
||||
const articleTableData = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam: {
|
||||
title: '',
|
||||
category_id: '',
|
||||
is_show: 1
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取文章列表
|
||||
*/
|
||||
const loadArticleList = (page: number = 1) => {
|
||||
articleTableData.loading = true
|
||||
articleTableData.page = page
|
||||
|
||||
getArticleList({
|
||||
page: articleTableData.page,
|
||||
limit: articleTableData.limit,
|
||||
...articleTableData.searchParam
|
||||
}).then(res => {
|
||||
articleTableData.loading = false
|
||||
articleTableData.data = res.data.data
|
||||
articleTableData.total = res.data.total
|
||||
}).catch(() => {
|
||||
articleTableData.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
loadArticleList()
|
||||
|
||||
const multipleSelection: any = ref([])
|
||||
|
||||
const handleSelectionChange = (val: any[]) => {
|
||||
multipleSelection.value = val
|
||||
}
|
||||
|
||||
const save = () => {
|
||||
diyStore.editComponent.articleIds = [];
|
||||
multipleSelection.value.forEach((item: any) => {
|
||||
diyStore.editComponent.articleIds.push(item.id)
|
||||
})
|
||||
showDialog.value = false
|
||||
}
|
||||
|
||||
defineExpose({})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.article-slider {
|
||||
.el-slider__input {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
@ -1,108 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\cms\app\adminapi\controller\article;
|
||||
|
||||
use addon\cms\app\service\admin\article\ArticleService;
|
||||
use core\base\BaseAdminController;
|
||||
use think\Response;
|
||||
|
||||
/**
|
||||
* 文章控制器
|
||||
* Class CmsArticle
|
||||
* @package app\adminapi\controller\article
|
||||
*/
|
||||
class Article extends BaseAdminController
|
||||
{
|
||||
/**
|
||||
* 文章列表
|
||||
* @return Response
|
||||
*/
|
||||
public function lists()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ 'title', '' ],
|
||||
[ 'category_id', '' ],
|
||||
[ 'sort', '' ],
|
||||
[ 'is_show', '' ],
|
||||
]);
|
||||
return success(( new ArticleService() )->getPage($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章详情
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function info(int $id)
|
||||
{
|
||||
return success(( new ArticleService() )->getInfo($id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加文章
|
||||
* @return Response
|
||||
*/
|
||||
public function add()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ 'title', '' ],
|
||||
[ 'category_id', '' ],
|
||||
[ 'intro', '' ],
|
||||
[ 'summary', '' ],
|
||||
[ 'image', '' ],
|
||||
[ 'author', '' ],
|
||||
[ 'content', '', false ],
|
||||
[ 'visit_virtual', 0 ],
|
||||
[ 'is_show', 1 ],
|
||||
[ 'sort', 0 ],
|
||||
]);
|
||||
$this->validate($data, 'addon\cms\app\validate\article\Article.add');
|
||||
$id = ( new ArticleService() )->add($data);
|
||||
return success('ADD_SUCCESS', [ 'id' => $id ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章编辑
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function edit(int $id)
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ 'title', '' ],
|
||||
[ 'category_id', '' ],
|
||||
[ 'intro', '' ],
|
||||
[ 'summary', '' ],
|
||||
[ 'image', '' ],
|
||||
[ 'author', '' ],
|
||||
[ 'content', '', false ],
|
||||
[ 'visit_virtual', 0 ],
|
||||
[ 'is_show', 1 ],
|
||||
[ 'sort', 0 ],
|
||||
]);
|
||||
$this->validate($data, 'addon\cms\app\validate\article\Article.edit');
|
||||
( new ArticleService() )->edit($id, $data);
|
||||
return success('EDIT_SUCCESS');
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章删除
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function del(int $id)
|
||||
{
|
||||
( new ArticleService() )->del($id);
|
||||
return success('DELETE_SUCCESS');
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,95 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\cms\app\adminapi\controller\article;
|
||||
|
||||
use addon\cms\app\service\admin\article\ArticleCategoryService;
|
||||
use core\base\BaseAdminController;
|
||||
use think\Response;
|
||||
|
||||
class ArticleCategory extends BaseAdminController
|
||||
{
|
||||
/**
|
||||
* 文章分类列表
|
||||
* @return Response
|
||||
*/
|
||||
public function lists()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ 'name', '' ],
|
||||
]);
|
||||
return success(( new ArticleCategoryService() )->getPage($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有分类(文章添加,编辑,索引)
|
||||
* @return Response
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
return success(( new ArticleCategoryService() )->getAll());
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章分类详情
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function info(int $id)
|
||||
{
|
||||
return success(( new ArticleCategoryService() )->getInfo($id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加文章分类
|
||||
* @return Response
|
||||
*/
|
||||
public function add()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ 'name', '' ],
|
||||
[ 'is_show', 1 ],
|
||||
[ 'sort', 0 ],
|
||||
]);
|
||||
$this->validate($data, 'addon\cms\app\validate\article\ArticleCategory.add');
|
||||
$id = ( new ArticleCategoryService() )->add($data);
|
||||
return success('ADD_SUCCESS', [ 'id' => $id ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章分类编辑
|
||||
* @param int $category_id //分类id
|
||||
* @return Response
|
||||
*/
|
||||
public function edit(int $category_id)
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ 'name', '' ],
|
||||
[ 'is_show', 1 ],
|
||||
[ 'sort', 0 ],
|
||||
]);
|
||||
$this->validate($data, 'addon\cms\app\validate\article\ArticleCategory.edit');
|
||||
( new ArticleCategoryService() )->edit($category_id, $data);
|
||||
return success('EDIT_SUCCESS');
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章分类删除
|
||||
* @param int $category_id
|
||||
* @return Response
|
||||
*/
|
||||
public function del(int $category_id)
|
||||
{
|
||||
( new ArticleCategoryService() )->del($category_id);
|
||||
return success('DELETE_SUCCESS');
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
use think\facade\Route;
|
||||
|
||||
use app\adminapi\middleware\AdminCheckRole;
|
||||
use app\adminapi\middleware\AdminCheckToken;
|
||||
use app\adminapi\middleware\AdminLog;
|
||||
|
||||
/**
|
||||
* 微官网
|
||||
*/
|
||||
Route::group('cms', function() {
|
||||
|
||||
/***************************************************** 文章管理 ****************************************************/
|
||||
|
||||
//文章列表
|
||||
Route::get('article', 'addon\cms\app\adminapi\controller\article\Article@lists');
|
||||
|
||||
//文章详情
|
||||
Route::get('article/:id', 'addon\cms\app\adminapi\controller\article\Article@info');
|
||||
|
||||
//添加文章
|
||||
Route::post('article', 'addon\cms\app\adminapi\controller\article\Article@add');
|
||||
|
||||
//编辑文章
|
||||
Route::put('article/:id', 'addon\cms\app\adminapi\controller\article\Article@edit');
|
||||
|
||||
//删除文章
|
||||
Route::delete('article/:id', 'addon\cms\app\adminapi\controller\article\Article@del');
|
||||
|
||||
/***************************************************** 文章分类管理 ****************************************************/
|
||||
|
||||
//文章分类列表
|
||||
Route::get('category', 'addon\cms\app\adminapi\controller\article\ArticleCategory@lists');
|
||||
|
||||
//所有文章分类
|
||||
Route::get('category/all', 'addon\cms\app\adminapi\controller\article\ArticleCategory@all');
|
||||
|
||||
//文章分类详情
|
||||
Route::get('category/:id', 'addon\cms\app\adminapi\controller\article\ArticleCategory@info');
|
||||
|
||||
//添加文章分类
|
||||
Route::post('category', 'addon\cms\app\adminapi\controller\article\ArticleCategory@add');
|
||||
|
||||
//编辑文章分类
|
||||
Route::put('category/:id', 'addon\cms\app\adminapi\controller\article\ArticleCategory@edit');
|
||||
|
||||
//删除文章分类
|
||||
Route::delete('category/:category_id', 'addon\cms\app\adminapi\controller\article\ArticleCategory@del');
|
||||
|
||||
})->middleware([
|
||||
AdminCheckToken::class,
|
||||
AdminCheckRole::class,
|
||||
AdminLog::class
|
||||
]);
|
||||
@ -1,59 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\cms\app\api\controller\article;
|
||||
|
||||
use addon\cms\app\service\api\article\ArticleService;
|
||||
use core\base\BaseApiController;
|
||||
use think\Response;
|
||||
|
||||
/**
|
||||
* 文章控制器
|
||||
* Class CmsArticle
|
||||
* @package app\api\controller\article
|
||||
*/
|
||||
class Article extends BaseApiController
|
||||
{
|
||||
/**
|
||||
* 文章列表
|
||||
* @return Response
|
||||
*/
|
||||
public function lists()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ 'title', '' ],
|
||||
[ 'category_id', '' ],
|
||||
]);
|
||||
return success(( new ArticleService() )->getPage($data));
|
||||
}
|
||||
|
||||
public function all()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ 'title', '' ],
|
||||
[ 'category_id', '' ],
|
||||
[ 'ids', [] ],
|
||||
[ 'limit', 0 ]
|
||||
]);
|
||||
return success(( new ArticleService() )->getAll($data, $data[ 'limit' ]));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章详情
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function info(int $id)
|
||||
{
|
||||
return success(( new ArticleService() )->getInfo($id));
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\cms\app\api\controller\article;
|
||||
|
||||
use addon\cms\app\service\api\article\ArticleCategoryService;
|
||||
use core\base\BaseApiController;
|
||||
use think\Response;
|
||||
|
||||
/**
|
||||
* 文章分类
|
||||
* Class CmsArticleCategory
|
||||
* @package app\api\controller\article
|
||||
*/
|
||||
class ArticleCategory extends BaseApiController
|
||||
{
|
||||
/**
|
||||
* 文章分类列表
|
||||
* @return Response
|
||||
*/
|
||||
public function lists()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ 'name', '' ],
|
||||
]);
|
||||
return success(( new ArticleCategoryService() )->getPage($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章分类详情
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function info(int $id)
|
||||
{
|
||||
return success(( new ArticleCategoryService() )->getInfo($id));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
use app\api\middleware\ApiCheckToken;
|
||||
use app\api\middleware\ApiLog;
|
||||
use app\api\middleware\ApiChannel;
|
||||
use think\facade\Route;
|
||||
|
||||
|
||||
/**
|
||||
* 微官网1
|
||||
*/
|
||||
Route::group('cms', function() {
|
||||
|
||||
/***************************************************** 文章管理 ****************************************************/
|
||||
|
||||
//文章列表
|
||||
Route::get('article', 'addon\cms\app\api\controller\article\Article@lists');
|
||||
|
||||
//文章详情
|
||||
Route::get('article/:id', 'addon\cms\app\api\controller\article\Article@info');
|
||||
|
||||
//文章
|
||||
Route::get('article/all', 'addon\cms\app\api\controller\article\Article@all');
|
||||
|
||||
/***************************************************** 文章分类管理 ****************************************************/
|
||||
|
||||
//文章分类列表
|
||||
Route::get('category', 'addon\cms\app\api\controller\article\ArticleCategory@lists');
|
||||
|
||||
//文章分类详情
|
||||
Route::get('category/:id', 'addon\cms\app\api\controller\article\ArticleCategory@info');
|
||||
|
||||
})->middleware(ApiChannel::class)
|
||||
->middleware(ApiCheckToken::class, false) //false表示不验证登录
|
||||
->middleware(ApiLog::class);
|
||||
@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'BASIC' => [
|
||||
'title' => get_lang('dict_diy.component_type_basic'),
|
||||
'list' => [
|
||||
'Article' => [
|
||||
'title' => '文章',
|
||||
'icon' => 'iconfont-iconwenzhang',
|
||||
'path' => 'edit-article',
|
||||
'support_page' => [],
|
||||
'uses' => 0,
|
||||
'sort' => 10007,
|
||||
'value' => [
|
||||
'sources' => 'initial',
|
||||
'count' => 8,
|
||||
'articleIds' => []
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'CMS_LINK' => [
|
||||
'key' => 'cms',
|
||||
'addon_title' => get_lang('dict_diy.cms_title'),
|
||||
'title' => get_lang('dict_diy.cms_link'),
|
||||
'child_list' => [
|
||||
[
|
||||
'name' => 'ARTICLE_LIST',
|
||||
'title' => get_lang('dict_diy.cms_link_article_list'),
|
||||
'url' => '/cms/pages/list',
|
||||
'is_share' => 1,
|
||||
'action' => ''
|
||||
],
|
||||
]
|
||||
],
|
||||
];
|
||||
@ -1,73 +0,0 @@
|
||||
<?php
|
||||
return [
|
||||
[
|
||||
'menu_name' => '微官网',
|
||||
'menu_key' => 'cms',
|
||||
'menu_type' => 0,
|
||||
'icon' => 'element-Tickets',
|
||||
'api_url' => '',
|
||||
'router_path' => 'cms',
|
||||
'view_path' => '',
|
||||
'methods' => '',
|
||||
'sort' => 100,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
'children' => [
|
||||
[
|
||||
'menu_name' => '文章管理',
|
||||
'menu_short_name' => '文章',
|
||||
'menu_key' => 'cms_article',
|
||||
'menu_type' => 0,
|
||||
'icon' => 'iconfont-iconwenzhangguanli1',
|
||||
'api_url' => '',
|
||||
'router_path' => 'article',
|
||||
'view_path' => '',
|
||||
'methods' => '',
|
||||
'sort' => 98,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
'children' => [
|
||||
[
|
||||
'menu_name' => '文章列表',
|
||||
'menu_key' => 'cms_article_list',
|
||||
'menu_type' => 1,
|
||||
'icon' => 'element-ChatDotSquare',
|
||||
'api_url' => 'cms/article',
|
||||
'router_path' => 'list',
|
||||
'view_path' => 'article/list',
|
||||
'methods' => 'get',
|
||||
'sort' => 100,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '文章添加/编辑',
|
||||
'menu_key' => 'cms_article_edit',
|
||||
'menu_type' => 1,
|
||||
'icon' => '',
|
||||
'api_url' => 'cms/article',
|
||||
'router_path' => 'edit',
|
||||
'view_path' => 'article/edit',
|
||||
'methods' => 'post',
|
||||
'sort' => 90,
|
||||
'status' => 1,
|
||||
'is_show' => 0,
|
||||
],
|
||||
[
|
||||
'menu_name' => '文章栏目',
|
||||
'menu_key' => 'cms_article_category',
|
||||
'menu_type' => 1,
|
||||
'icon' => 'element-CollectionTag',
|
||||
'api_url' => 'article/category',
|
||||
'router_path' => 'category',
|
||||
'view_path' => 'article/category',
|
||||
'methods' => 'get',
|
||||
'sort' => 80,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'listen' => [
|
||||
'WapIndex' => [ 'addon\cms\app\listener\WapIndexListener' ],
|
||||
]
|
||||
];
|
||||
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
|
||||
];
|
||||
@ -1,20 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
'dict_menu_admin' => [
|
||||
'article' => 'article',
|
||||
'article_list' => 'article list',
|
||||
'article_edit' => 'article edit',
|
||||
'article_category' => 'article category',
|
||||
],
|
||||
|
||||
];
|
||||
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
'validate_article' => [
|
||||
'title_require' => 'title is require',
|
||||
'title_max' => 'title must not be exceed 20 points',
|
||||
'intro_max' => 'intro must not be exceed 50 points',
|
||||
'summary_max' => 'summary must not be exceed 50 points',
|
||||
'image_max' => 'image is exceed max',
|
||||
'author_max' => 'author must not be exceed 20 points',
|
||||
'is_show_number' => 'is_show must be a number',
|
||||
'is_show_between' => 'is_show must be 0 or 1',
|
||||
'sort_number' => 'sort must be a number',
|
||||
'sort_between' => 'sort must not be exceed 10000',
|
||||
'cate_name_require' => 'cate_name is require',
|
||||
'cate_name_max' => 'cate_name must not be exceed 120 points',
|
||||
]
|
||||
];
|
||||
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
|
||||
];
|
||||
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
'dict_diy' => [
|
||||
'cms_title' => '微官网',
|
||||
'cms_link' => '微官网链接',
|
||||
'cms_link_article_list' => '文章资讯',
|
||||
],
|
||||
'dict_wap_index' => [
|
||||
'cms' => '微官网',
|
||||
'cms_desc' => '文章栏目管理',
|
||||
],
|
||||
];
|
||||
@ -1,30 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
'validate_article' => [
|
||||
'title_require' => '文章标题必须填写',
|
||||
'title_max' => '文章标题不能超过20个字符',
|
||||
'intro_max' => '文章简介不能超过50个字符',
|
||||
'summary_max' => '文章摘要不能超过50个字符',
|
||||
'image_max' => '图片路径太长',
|
||||
'author_max' => '文章作者不能超过20个字符',
|
||||
'is_show_number' => '是否显示必须是数字',
|
||||
'is_show_between' => '是否显示只能是0或者1',
|
||||
'sort_number' => '排序号必须是数字',
|
||||
'sort_between' => '排序号不能超过10000',
|
||||
'cate_name_require' => '栏目名称必须填写',
|
||||
'cate_name_max' => '栏目不能超过20个字符',
|
||||
'category_id_require' => '文章栏目必须填写',
|
||||
'category_id_num' => '文章栏目必须是整数',
|
||||
'content_require' => '文章内容必须填写',
|
||||
],
|
||||
];
|
||||
@ -1,31 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\cms\app\listener;
|
||||
|
||||
/**
|
||||
* 手机端首页加载事件
|
||||
*/
|
||||
class WapIndexListener
|
||||
{
|
||||
public function handle()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'key' => 'cms',
|
||||
"title" => get_lang("dict_wap_index.cms"),
|
||||
'desc' => get_lang("dict_wap_index.cms_desc"),
|
||||
"url" => "/cms/pages/list",
|
||||
'icon'=>'addon/cms/icon.png'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -1,139 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\cms\app\model\article;
|
||||
|
||||
use app\dict\sys\FileDict;
|
||||
use core\base\BaseModel;
|
||||
use think\db\Query;
|
||||
use think\model\relation\HasOne;
|
||||
|
||||
/**
|
||||
* 文章模型
|
||||
* Class CmsArticle
|
||||
* @package app\model\article
|
||||
*/
|
||||
class CmsArticle extends BaseModel
|
||||
{
|
||||
|
||||
/**
|
||||
* 数据表主键
|
||||
* @var string
|
||||
*/
|
||||
protected $pk = 'id';
|
||||
|
||||
/**
|
||||
* 模型名称
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'cms_article';
|
||||
|
||||
/**
|
||||
* @return HasOne
|
||||
*/
|
||||
public function cmsArticleCategory()
|
||||
{
|
||||
return $this->hasOne(CmsArticleCategory::class, 'category_id', 'category_id')->joinType('left')->withField('category_id, name')->bind([ 'category_name' => 'name' ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章分类搜索器
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchCategoryIdAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$query->where('category_id', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章标题搜索器
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchTitleAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$query->where('title', 'like', '%' . $value . '%');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章标题搜索器
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchIsShowAttr($query, $value, $data)
|
||||
{
|
||||
if ($value != '') {
|
||||
$query->where('is_show', $value);
|
||||
}
|
||||
}
|
||||
|
||||
public function searchIdsAttr(Query $query, $value, $data)
|
||||
{
|
||||
if (!empty($value)) {
|
||||
$query->whereIn('id', $data[ 'ids' ]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 文章标题搜索器
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchSortAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$query->where('sort', $value);
|
||||
}
|
||||
}
|
||||
|
||||
public function getArticleUrlAttr($value, $data)
|
||||
{
|
||||
|
||||
$wap_domain = !empty(env("system.wap_domain")) ? preg_replace('#/$#', '', env("system.wap_domain")) : request()->domain();
|
||||
$web_domain = !empty(env("system.web_domain")) ? preg_replace('#/$#', '', env("system.web_domain")) : request()->domain();
|
||||
|
||||
return [
|
||||
'wap_url' => $wap_domain . "/wap/cms/pages/detail?id={$data['id']}",
|
||||
'web_url' => $web_domain . "/web/article/detail?id={$data['id']}"
|
||||
];
|
||||
}
|
||||
|
||||
public function getImageThumbBigAttr($value, $data)
|
||||
{
|
||||
if ($data[ 'image' ] != '') {
|
||||
return get_thumb_images($data[ 'image' ], FileDict::BIG);
|
||||
}
|
||||
}
|
||||
|
||||
public function getImageThumbMidAttr($value, $data)
|
||||
{
|
||||
if ($data[ 'image' ] != '') {
|
||||
return get_thumb_images($data[ 'image' ], FileDict::MID);
|
||||
}
|
||||
}
|
||||
|
||||
public function getImageThumbSmallAttr($value, $data)
|
||||
{
|
||||
if ($data[ 'image' ] != '') {
|
||||
return get_thumb_images($data[ 'image' ], FileDict::SMALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\cms\app\model\article;
|
||||
|
||||
use core\base\BaseModel;
|
||||
|
||||
/**
|
||||
* 文章栏目模型
|
||||
* Class CmsArticleCategory
|
||||
* @package app\model\article
|
||||
*/
|
||||
class CmsArticleCategory extends BaseModel
|
||||
{
|
||||
|
||||
/**
|
||||
* 数据表主键
|
||||
* @var string
|
||||
*/
|
||||
protected $pk = 'category_id';
|
||||
|
||||
/**
|
||||
* 模型名称
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'cms_article_category';
|
||||
|
||||
/**
|
||||
* 文章分类名称搜索器
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchNameAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$query->where([ [ 'name', 'like', "%$value%" ] ]);
|
||||
}
|
||||
}
|
||||
|
||||
public function getArticleNumAttr($value, $data)
|
||||
{
|
||||
return ( new CmsArticle() )->where([ [ 'category_id', '=', $data[ 'category_id' ] ] ])->count();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,102 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\cms\app\service\admin\article;
|
||||
|
||||
use addon\cms\app\model\article\CmsArticleCategory;
|
||||
use core\base\BaseAdminService;
|
||||
|
||||
/**
|
||||
* 文章分类(栏目)服务层
|
||||
* Class ArticleService
|
||||
* @package app\service\admin\article
|
||||
*/
|
||||
class ArticleCategoryService extends BaseAdminService
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->model = new CmsArticleCategory();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章分类列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getPage(array $where = [])
|
||||
{
|
||||
|
||||
$field = 'category_id, name, sort, is_show, create_time, update_time';
|
||||
$order = 'create_time desc';
|
||||
$search_model = $this->model->withSearch(['name'], $where)->field($field)->order($order)->append(["article_num"]);
|
||||
return $this->pageQuery($search_model);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有分类(文章添加)
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
$field = 'category_id, name, sort';
|
||||
$order = 'sort desc';
|
||||
return $this->model->where([['is_show', '=', 1]])->field($field)->order($order)->select()->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章分类信息
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function getInfo(int $id)
|
||||
{
|
||||
$field = 'category_id, name, sort, is_show, create_time, update_time';
|
||||
|
||||
return $this->model->field($field)->where([['category_id', '=', $id]])->append(["article_num"])->findOrEmpty()->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加文章分类
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function add(array $data)
|
||||
{
|
||||
$res = $this->model->create($data);
|
||||
return $res->category_id;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章分类编辑
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @return true
|
||||
*/
|
||||
public function edit(int $id, array $data)
|
||||
{
|
||||
$data['update_time'] = time();
|
||||
$this->model->where([['category_id', '=', $id]])->update($data);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文章分类
|
||||
* @param int $id
|
||||
* @return bool
|
||||
*/
|
||||
public function del(int $id)
|
||||
{
|
||||
return $this->model->where([['category_id', '=', $id]])->delete();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,92 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\cms\app\service\admin\article;
|
||||
|
||||
use addon\cms\app\model\article\CmsArticle;
|
||||
use core\base\BaseAdminService;
|
||||
|
||||
/**
|
||||
* 文章服务层
|
||||
* Class ArticleService
|
||||
* @package app\service\admin\article
|
||||
*/
|
||||
class ArticleService extends BaseAdminService
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->model = new CmsArticle();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getPage(array $where = [])
|
||||
{
|
||||
$field = 'id, category_id, title, intro, summary, image, author, content, visit, visit_virtual, is_show, sort, create_time, update_time';
|
||||
$order = 'create_time desc';
|
||||
$search_model = $this->model->withSearch([ 'title', 'category_id', 'is_show'], $where)->with('cmsArticleCategory')->field($field)->order($order)->append(['article_url','image_thumb_small']);
|
||||
return $this->pageQuery($search_model);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章信息
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function getInfo(int $id)
|
||||
{
|
||||
$field = 'id, category_id, title, intro, summary, image, author, content, visit, visit_virtual, is_show, sort, create_time, update_time';
|
||||
|
||||
return $this->model->where([ [ 'id', '=', $id ]])->with('cmsArticleCategory')->field($field)->append(['image_thumb_small'])->findOrEmpty()->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加文章
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function add(array $data)
|
||||
{
|
||||
$data[ 'create_time' ] = time();
|
||||
$res = $this->model->create($data);
|
||||
return $res->id;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章编辑
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @return true
|
||||
*/
|
||||
public function edit(int $id, array $data)
|
||||
{
|
||||
$data[ 'update_time' ] = time();
|
||||
$this->model->where([ [ 'id', '=', $id ]])->update($data);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文章
|
||||
* @param int $id
|
||||
* @return bool
|
||||
*/
|
||||
public function del(int $id)
|
||||
{
|
||||
return $this->model->where([ [ 'id', '=', $id ] ])->delete();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\cms\app\service\api\article;
|
||||
|
||||
use addon\cms\app\model\article\CmsArticleCategory;
|
||||
use core\base\BaseApiService;
|
||||
|
||||
/**
|
||||
* 文章分类(栏目)服务层
|
||||
* Class ArticleService
|
||||
* @package app\service\api\article
|
||||
*/
|
||||
class ArticleCategoryService extends BaseApiService
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->model = new CmsArticleCategory();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章分类列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getPage(array $where = [])
|
||||
{
|
||||
$field = 'category_id, name, sort, is_show, create_time, update_time';
|
||||
$order = 'create_time desc';
|
||||
$search_model = $this->model->withSearch(['name'], $where)->field($field)->order($order);
|
||||
return $this->pageQuery($search_model);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章分类信息
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function getInfo(int $id)
|
||||
{
|
||||
$field = 'category_id, name, sort, is_show, create_time, update_time';
|
||||
return $this->model->field($field)->where([['category_id', '=', $id]])->findOrEmpty()->toArray();
|
||||
}
|
||||
}
|
||||
@ -1,74 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\cms\app\service\api\article;
|
||||
|
||||
use addon\cms\app\model\article\CmsArticle;
|
||||
use core\base\BaseApiService;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
|
||||
/**
|
||||
* 文章服务层
|
||||
* Class ArticleService
|
||||
* @package app\service\api\article
|
||||
*/
|
||||
class ArticleService extends BaseApiService
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->model = new CmsArticle();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getPage(array $where = [])
|
||||
{
|
||||
$field = 'id, category_id, title, intro, summary, image, author, content, visit, visit_virtual, is_show, sort, create_time, update_time';
|
||||
$order = 'create_time desc';
|
||||
$search_model = $this->model->withSearch([ 'title', 'category_id'], $where)->with('cmsArticleCategory')->field($field)->order($order)->append(['image_thumb_mid']);
|
||||
return $this->pageQuery($search_model);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章列表
|
||||
* @param array $where
|
||||
* @param int $limit
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getAll(array $where = [], int $limit = 0){
|
||||
$field = 'id, category_id, title, intro, summary, image, author, content, visit, visit_virtual, is_show, sort, create_time, update_time';
|
||||
$order = 'create_time desc';
|
||||
return $this->model->where([ ['is_show', '=', 1]])->withSearch([ 'title', 'category_id', 'ids' ], $where)->limit($limit)->with('cmsArticleCategory')->field($field)->append(['image_thumb_mid'])->order($order)->select()->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章信息
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function getInfo(int $id)
|
||||
{
|
||||
$field = 'id, category_id, title, intro, summary, image, author, content, visit, visit_virtual, is_show, sort, create_time, update_time';
|
||||
|
||||
return $this->model->with('cmsArticleCategory')->field($field)->where([ [ 'id', '=', $id ] ])->append(['image_thumb_big'])->findOrEmpty()->toArray();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\cms\app\validate\article;
|
||||
|
||||
|
||||
use think\Validate;
|
||||
|
||||
/**
|
||||
* Class CmsArticle
|
||||
* @package app\validate\article
|
||||
*/
|
||||
class Article extends Validate
|
||||
{
|
||||
|
||||
//用户名或密码的规范可能是从数据库中获取的
|
||||
protected $rule = [
|
||||
'title' => 'require|max:20',
|
||||
'intro' => 'max:50',
|
||||
'summary' => 'max:50',
|
||||
'image' => 'max:100',
|
||||
'author' => 'max:20',
|
||||
'is_show' => 'number|between:0,1',
|
||||
'sort' => 'number|between:0,10000',
|
||||
'category_id' => 'number|require',
|
||||
'content' => 'require',
|
||||
];
|
||||
|
||||
protected $message = [
|
||||
'title.require' => 'validate_article.title_require',
|
||||
'title.max' => 'validate_article.title_max',
|
||||
'intro.max' => 'validate_article.intro_max',
|
||||
'summary.max' => 'validate_article.summary_max',
|
||||
'image.max' => 'validate_article.image_max',
|
||||
'author.max' => 'validate_article.author_max',
|
||||
'is_show.number' => 'validate_article.is_show_number',
|
||||
'is_show.between' => 'validate_article.is_show_between',
|
||||
'sort.number' => 'validate_article.sort_number',
|
||||
'sort.between' => 'validate_article.sort_between',
|
||||
'category_id.require' => 'validate_article.category_id_require',
|
||||
'category_id.number' => 'validate_article.category_id_number',
|
||||
'content.require' => 'validate_article.content_require',
|
||||
];
|
||||
|
||||
protected $scene = [
|
||||
'add' => ['title', 'intro', 'summary', 'image', 'author', 'is_show', 'sort', 'content', 'category_id'],
|
||||
'edit' => ['title', 'intro', 'summary', 'image', 'author', 'is_show', 'sort', 'content', 'category_id'],
|
||||
];
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\cms\app\validate\article;
|
||||
|
||||
|
||||
use think\Validate;
|
||||
|
||||
/**
|
||||
* 文章分类(栏目)验证
|
||||
* Class CmsArticle
|
||||
* @package app\validate\article
|
||||
*/
|
||||
class ArticleCategory extends Validate
|
||||
{
|
||||
|
||||
//用户名或密码的规范可能是从数据库中获取的
|
||||
protected $rule = [
|
||||
'name' => 'require|max:20',
|
||||
'is_show' => 'number|between:0,1',
|
||||
'sort' => 'number|between:0,10000'
|
||||
];
|
||||
|
||||
protected $message = [
|
||||
'name.require' => 'validate_article.cate_name_require',
|
||||
'name.max' => 'validate_article.cate_name_max',
|
||||
'is_show.number' => 'validate_article.is_show_number',
|
||||
'is_show.between' => 'validate_article.is_show_between',
|
||||
'sort.number' => 'validate_article.sort_number',
|
||||
'sort.between' => 'validate_article.sort_between',
|
||||
];
|
||||
|
||||
protected $scene = [
|
||||
'add' => ['name', 'is_show', 'sort'],
|
||||
'edit' => ['name', 'is_show', 'sort'],
|
||||
];
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
{
|
||||
"title": "微官网",
|
||||
"desc": "文章栏目管理",
|
||||
"key": "cms",
|
||||
"version": "1.0.1",
|
||||
"author": "niucloud",
|
||||
"type": "app",
|
||||
"support_app": ""
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
return [
|
||||
'pages' => <<<EOT
|
||||
// PAGE_BEGIN
|
||||
{
|
||||
"path": "{{addon_name}}/pages/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "%{{addon_name}}.pages.list%"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "{{addon_name}}/pages/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "%{{addon_name}}.pages.detail%"
|
||||
}
|
||||
}
|
||||
// PAGE_END
|
||||
EOT
|
||||
];
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 128 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB |
@ -1,37 +0,0 @@
|
||||
|
||||
DROP TABLE IF EXISTS `{{prefix}}cms_article`;
|
||||
CREATE TABLE `{{prefix}}cms_article` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '文章id',
|
||||
`category_id` int(11) NOT NULL COMMENT '文章分类',
|
||||
`title` varchar(255) NOT NULL COMMENT '文章标题',
|
||||
`intro` varchar(255) NOT NULL DEFAULT '' COMMENT '简介',
|
||||
`summary` varchar(255) NOT NULL DEFAULT '' COMMENT '文章摘要',
|
||||
`image` varchar(128) NOT NULL DEFAULT '' COMMENT '文章图片',
|
||||
`author` varchar(255) NOT NULL DEFAULT '' COMMENT '作者',
|
||||
`content` text DEFAULT NULL COMMENT '文章内容',
|
||||
`visit` int(11) NOT NULL DEFAULT '0' COMMENT '实际浏览量',
|
||||
`visit_virtual` int(11) NOT NULL DEFAULT '0' COMMENT '初始浏览量',
|
||||
`is_show` tinyint(4) NOT NULL DEFAULT '1' COMMENT '是否显示:1-是.0-否',
|
||||
`sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序',
|
||||
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
|
||||
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `IDX_article_category_id` (`category_id`),
|
||||
KEY `IDX_article_create_time` (`create_time`),
|
||||
KEY `IDX_article_is_show` (`is_show`),
|
||||
KEY `IDX_ns_cms_article_sort` (`sort`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章表';
|
||||
|
||||
DROP TABLE IF EXISTS `{{prefix}}cms_article_category`;
|
||||
CREATE TABLE `{{prefix}}cms_article_category` (
|
||||
`category_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '文章分类id',
|
||||
`name` varchar(255) NOT NULL DEFAULT '' COMMENT '分类名称',
|
||||
`sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序',
|
||||
`is_show` tinyint(4) NOT NULL DEFAULT '1' COMMENT '是否显示:1-是;0-否',
|
||||
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
|
||||
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
|
||||
PRIMARY KEY (`category_id`),
|
||||
KEY `create_time` (`create_time`),
|
||||
KEY `is_show` (`is_show`),
|
||||
KEY `sort` (`sort`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章分类表';
|
||||
@ -1,4 +0,0 @@
|
||||
|
||||
DROP TABLE IF EXISTS `{{prefix}}cms_article`;
|
||||
|
||||
DROP TABLE IF EXISTS `{{prefix}}cms_article_category`;
|
||||
@ -1,29 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 文章列表
|
||||
*/
|
||||
export function getArticleList(params: Record<string, any>) {
|
||||
return request.get('cms/article', params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章列表
|
||||
*/
|
||||
export function getArticleAll(params: Record<string, any>) {
|
||||
return request.get('cms/article/all', params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章详情
|
||||
*/
|
||||
export function getArticleDetail(id: number) {
|
||||
return request.get(`cms/article/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章分类
|
||||
*/
|
||||
export function getArticleCategory() {
|
||||
return request.get('cms/category')
|
||||
}
|
||||
@ -1,132 +0,0 @@
|
||||
<template>
|
||||
<view :style="warpCss">
|
||||
<view v-for="(item,index) in articleList" :key="item.id"
|
||||
:class="['item flex align-center p-[20rpx]',{'border-solid border-t-0 border-l-0 border-r-0 border-b border-gray-200 mb-[20rpx]': articleList.length-1 !== index}] "
|
||||
@click="toLink(item.id)" :style="itemCss">
|
||||
<u--image width="260rpx" height="200rpx" :src="img(item.image)" v-if="item.image" model="aspectFill">
|
||||
<template #error>
|
||||
<u-icon name="photo" color="#999" size="50"></u-icon>
|
||||
</template>
|
||||
</u--image>
|
||||
<view class="flex-1 flex flex-col justify-between ml-[20rpx]">
|
||||
<view class="text-[32rpx] leading-[1.3] multi-hidden mt-[4rpx]">{{item.title}}</view>
|
||||
<view class="text-[28rpx] using-hidden mb-[auto] mt-[20rpx] text-gray-500">{{item.summary}}</view>
|
||||
<view class="text-[24rpx] text-gray-400 flex justify-between mt-[10rpx]">
|
||||
<text>{{item.create_time}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 文章
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import { redirect, img } from '@/utils/common';
|
||||
import useDiyStore from '@/app/stores/diy';
|
||||
import { getArticleAll } from '@/cms/api/article';
|
||||
|
||||
const props = defineProps(['component', 'index', 'pullDownRefresh']);
|
||||
const diyStore = useDiyStore();
|
||||
const articleList = ref<Array<any>>([]);
|
||||
|
||||
const diyComponent = computed(() => {
|
||||
if (diyStore.mode == 'decorate') {
|
||||
return diyStore.value[props.index];
|
||||
} else {
|
||||
return props.component;
|
||||
}
|
||||
})
|
||||
|
||||
const warpCss = computed(() => {
|
||||
var style = '';
|
||||
if (diyComponent.value.componentBgColor) style += 'background-color:' + diyComponent.value.componentBgColor + ';';
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;';
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;';
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;';
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;';
|
||||
return style;
|
||||
})
|
||||
|
||||
const itemCss = computed(() => {
|
||||
var style = '';
|
||||
if (diyComponent.value.elementBgColor) style += 'background-color:' + diyComponent.value.elementBgColor + ';';
|
||||
if (diyComponent.value.topElementRounded) style += 'border-top-left-radius:' + diyComponent.value.topElementRounded * 2 + 'rpx;';
|
||||
if (diyComponent.value.topElementRounded) style += 'border-top-right-radius:' + diyComponent.value.topElementRounded * 2 + 'rpx;';
|
||||
if (diyComponent.value.bottomElementRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomElementRounded * 2 + 'rpx;';
|
||||
if (diyComponent.value.bottomElementRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomElementRounded * 2 + 'rpx;';
|
||||
return style;
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.pullDownRefresh,
|
||||
(newValue, oldValue) => {
|
||||
// 处理下拉刷新业务
|
||||
}
|
||||
)
|
||||
|
||||
const getArticleListFn = () => {
|
||||
interface dataStructure {
|
||||
ids ?: Array<number>,
|
||||
limit ?: number
|
||||
}
|
||||
let data : dataStructure = {};
|
||||
|
||||
if (diyComponent.value.sources == "diy")
|
||||
data.ids = diyComponent.value.articleIds;
|
||||
else
|
||||
data.limit = diyComponent.value.count;
|
||||
|
||||
interface takeDataStructure {
|
||||
data : Array<Object>,
|
||||
msg : string,
|
||||
code : number
|
||||
}
|
||||
getArticleAll(data).then((res : takeDataStructure) => {
|
||||
articleList.value = res.data;
|
||||
});
|
||||
}
|
||||
|
||||
const refresh = () => {
|
||||
if (diyStore.mode == 'decorate') {
|
||||
let obj = {
|
||||
image: "",
|
||||
summary: "文章摘要",
|
||||
title: "文章标题",
|
||||
create_time: "2023-03-28 09:00:00"
|
||||
};
|
||||
articleList.value.push(obj);
|
||||
articleList.value.push(obj);
|
||||
} else {
|
||||
getArticleListFn();
|
||||
}
|
||||
}
|
||||
|
||||
refresh();
|
||||
const toLink = (id : string) => {
|
||||
redirect({ url: '/cms/pages/detail', param: { id } })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* 单行超出隐藏 */
|
||||
.using-hidden {
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
white-space: break-spaces;
|
||||
}
|
||||
|
||||
/* 多行超出隐藏 */
|
||||
.multi-hidden {
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
</style>
|
||||
@ -1,2 +0,0 @@
|
||||
{
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
{
|
||||
"pages.list": "资讯中心",
|
||||
"pages.detail": "文章详情"
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
{
|
||||
"detail": "文章详情",
|
||||
"abstract": "摘要",
|
||||
"loadingText": "正在加载"
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
{
|
||||
"list": "文章列表",
|
||||
"noData": "~ 暂无数据 ~",
|
||||
"all": "全部",
|
||||
"end": "-- 到底了 --",
|
||||
"searchPlaceholder": "请输入搜索关键词"
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
<template>
|
||||
<view class="bg-white">
|
||||
<block v-if="!loading">
|
||||
<view class="border-solid border-t-0 border-l-0 border-r-0 border-b-[1px] border-gray-200 p-[10px]">
|
||||
<view class="text-[16px]">
|
||||
{{articleDetail.title}}
|
||||
</view>
|
||||
<view class="flex align-center justify-between text-[12px] text-gray-400 mt-[15px]">
|
||||
<text>{{articleDetail.create_time}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mx-[10px] my-[10px] bg-gray-100 p-[8px] text-[14px] rounded-[5px] leading-[1.3]">
|
||||
{{t('abstract')}}:{{articleDetail.summary}}
|
||||
</view>
|
||||
<view class="px-[10px] pd-[10px]">
|
||||
<u-parse :content="articleDetail.content" :tagStyle="style"></u-parse>
|
||||
</view>
|
||||
</block>
|
||||
<u-loading-page bg-color="rgb(248,248,248)" :loading="loading" fontSize="16" color="#333" :loadingText="t('loadingText')"></u-loading-page>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { t } from '@/locale'
|
||||
import { getArticleDetail } from '@/cms/api/article';
|
||||
import { useShare } from '@/hooks/useShare'
|
||||
|
||||
const { setShare, onShareAppMessage, onShareTimeline } = useShare()
|
||||
onShareAppMessage()
|
||||
onShareTimeline()
|
||||
|
||||
let articleDetail = ref<Array<any>>([]);
|
||||
let loading = ref<boolean>(true);
|
||||
let style = {
|
||||
h2: 'margin-bottom: 15px;',
|
||||
p: 'margin-bottom: 10px;line-height: 1.5;',
|
||||
img: 'margin: 10px 0;',
|
||||
};
|
||||
onLoad((option) => {
|
||||
loading.value = true;
|
||||
getArticleDetail(option.id).then((res) => {
|
||||
articleDetail.value = res.data;
|
||||
loading.value = false;
|
||||
let share = {
|
||||
title: articleDetail.value.title,
|
||||
desc: articleDetail.value.intro,
|
||||
url: articleDetail.value.image
|
||||
}
|
||||
uni.setNavigationBarTitle({
|
||||
title: articleDetail.value.title
|
||||
})
|
||||
setShare({
|
||||
wechat: {
|
||||
...share
|
||||
},
|
||||
weapp: {
|
||||
...share
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
@ -1,164 +0,0 @@
|
||||
<template>
|
||||
<view class="bg-gray-100 min-h-[100vh]">
|
||||
<view class="fixed top-0 inset-x-0 z-10">
|
||||
<view class='p-[10px] bg-white border-solid border-t-0 border-l-0 border-r-0 border-b-[1px] border-gray-200'>
|
||||
<u-search :placeholder="t('searchPlaceholder')" actionText :actionStyle="{'width':0,'margin':0}" v-model="articleTitle" @clickIcon="searchFn"></u-search>
|
||||
</view>
|
||||
<scroll-view :scroll-x="true" :enable-flex="true"
|
||||
class="nav-list bg-white align-center px-[10px] box-border">
|
||||
<view class="flex scroll-view-wrap">
|
||||
<view
|
||||
:class="['nav-item text-[14px] mx-[5px] h-[30px] leading-[30px] my-[5px] border-t-0 border-l-0 border-r-0',{'border-solid border-b-[2px] active': currCategoryId==item.category_id}]"
|
||||
@click="loadCategory(item.category_id)" v-for="(item,index) in categoryList"
|
||||
:key="item.category_id">
|
||||
{{item.name}}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<mescroll-body ref="mescrollRef" @init="mescrollInit" top="220rpx" @down="downCallback" @up="getArticleListFn">
|
||||
<view v-for="(item,index) in articleList" :key="item.id"
|
||||
:class="['bg-white flex align-center p-[10px]',{'border-solid border-t-0 border-l-0 border-r-0 border-b-[1px] border-gray-200': articleList.length-1 !== index}] "
|
||||
@click="toLink(item.id)">
|
||||
<u--image width="174rpx" height="174rpx" :src="img(item.image)" model="aspectFill">
|
||||
<template #error>
|
||||
<u-icon name="photo" color="#999" size="50"></u-icon>
|
||||
</template>
|
||||
</u--image>
|
||||
<view class="flex-1 flex flex-col justify-between ml-[10px]">
|
||||
<view class="text-[16px] leading-[1.3] multi-hidden mt-[2px]">{{item.title}}</view>
|
||||
<view class="text-[14px] using-hidden mb-[10px] mt-[10px] text-gray-500">{{item.summary}}</view>
|
||||
<view class="text-[12px] text-gray-400 flex justify-between mb-[5px]">
|
||||
<text class="">{{item.create_time}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<mescroll-empty v-if="!articleList.length && loading"></mescroll-empty>
|
||||
</mescroll-body>
|
||||
<tabbar />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { t } from '@/locale'
|
||||
import { redirect, img } from '@/utils/common';
|
||||
import { getArticleList, getArticleCategory } from '@/cms/api/article';
|
||||
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue';
|
||||
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue';
|
||||
import useMescroll from '@/components/mescroll/hooks/useMescroll.js';
|
||||
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app';
|
||||
import { useShare } from '@/hooks/useShare'
|
||||
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom);
|
||||
const { setShare, onShareAppMessage, onShareTimeline } = useShare()
|
||||
setShare()
|
||||
onShareAppMessage()
|
||||
onShareTimeline()
|
||||
|
||||
let categoryList = ref<Array<Object>>([]);
|
||||
let articleList = ref<Array<any>>([]);
|
||||
let currCategoryId = ref<number | string>('');
|
||||
let articleTitle = ref<string>('');
|
||||
let mescrollRef = ref(null);
|
||||
let loading = ref<boolean>(false);
|
||||
|
||||
interface acceptingDataStructure {
|
||||
data : acceptingDataItemStructure,
|
||||
msg : string,
|
||||
code : number
|
||||
}
|
||||
interface acceptingDataItemStructure {
|
||||
data : object,
|
||||
[propName : string] : number | string | object
|
||||
}
|
||||
onLoad(async () => {
|
||||
await getArticleCategory().then((res : acceptingDataStructure) => {
|
||||
const initData = { name: t("all"), category_id: '' };
|
||||
categoryList.value.push(initData);
|
||||
categoryList.value = categoryList.value.concat(res.data.data);
|
||||
});
|
||||
})
|
||||
|
||||
interface mescrollStructure {
|
||||
num : number,
|
||||
size : number,
|
||||
endSuccess : Function,
|
||||
[propName : string] : any
|
||||
}
|
||||
const getArticleListFn = (mescroll : mescrollStructure) => {
|
||||
loading.value = false;
|
||||
let data : object = {
|
||||
category_id: currCategoryId.value,
|
||||
title: articleTitle.value,
|
||||
page: mescroll.num,
|
||||
limit: mescroll.size
|
||||
};
|
||||
|
||||
getArticleList(data).then((res : acceptingDataStructure) => {
|
||||
let newArr = (res.data.data as Array<Object>);
|
||||
//设置列表数据
|
||||
if (mescroll.num == 1) {
|
||||
articleList.value = []; //如果是第一页需手动制空列表
|
||||
}
|
||||
articleList.value = articleList.value.concat(newArr);
|
||||
mescroll.endSuccess(newArr.length);
|
||||
loading.value = true;
|
||||
}).catch(() => {
|
||||
loading.value = true;
|
||||
mescroll.endErr(); // 请求失败, 结束加载
|
||||
})
|
||||
}
|
||||
|
||||
const loadCategory = (id : string) => {
|
||||
currCategoryId.value = id;
|
||||
getMescroll().resetUpScroll();
|
||||
}
|
||||
|
||||
const searchFn = () => {
|
||||
getMescroll().resetUpScroll();
|
||||
}
|
||||
|
||||
const toLink = (id : string) => {
|
||||
redirect({ url: '/cms/pages/detail', param: { id } })
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
getMescroll().optUp.textNoMore = t("end");
|
||||
}, 500)
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.nav-item.active {
|
||||
color: $u-primary;
|
||||
}
|
||||
|
||||
.scroll-view-wrap {
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
/* 单行超出隐藏 */
|
||||
.using-hidden {
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
white-space: break-spaces;
|
||||
}
|
||||
|
||||
/* 多行超出隐藏 */
|
||||
.multi-hidden {
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
</style>
|
||||
@ -1,27 +0,0 @@
|
||||
/**
|
||||
* 文章列表
|
||||
*/
|
||||
export function getArticleList(params: Record<string, any>) {
|
||||
return request.get('cms/article', params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章列表
|
||||
*/
|
||||
export function getArticleAll(params: Record<string, any>) {
|
||||
return request.get('cms/article/all', params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章详情
|
||||
*/
|
||||
export function getArticleDetail(id: number) {
|
||||
return request.get(`cms/article/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章分类
|
||||
*/
|
||||
export function getArticleCategory() {
|
||||
return request.get('cms/category')
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
{
|
||||
"title": "文章"
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
{
|
||||
"title": "文章"
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
{
|
||||
"pages": {
|
||||
"cms": {
|
||||
"article": {
|
||||
"list": "文章",
|
||||
"detail": "文章"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,86 +0,0 @@
|
||||
<template>
|
||||
<div class="w-full min-h-[100%] main-container pt-5">
|
||||
<div class="mt-[20px] mb-[50px]" v-if="articleDetail">
|
||||
<el-breadcrumb :separator-icon="ArrowRight">
|
||||
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item :to="{ path: '/cms/article/list' }">文章</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>{{ articleDetail.category_name }}</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<div>
|
||||
<p class="py-[20px] text-center text-[24px]">{{ articleDetail.title }}</p>
|
||||
<div class="flex justify-center">
|
||||
<!-- <div class="mr-3 flex items-center text-gray-500 text-sm text-[#999]"><el-icon><View /></el-icon> <span class="ml-1">浏览量:158</span></div> -->
|
||||
<div class="mr-3 flex items-center text-gray-500 text-sm text-[#999]">
|
||||
<el-icon>
|
||||
<Clock />
|
||||
</el-icon>
|
||||
<span class="ml-1">时间:{{ articleDetail.create_time }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-[50px]" v-html="articleDetail.content"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { getArticleDetail } from '@/cms/api/article'
|
||||
import { ArrowRight } from '@element-plus/icons-vue'
|
||||
import { nMounted } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const Route = useRoute(); //获取到值
|
||||
const articleDetail = ref();
|
||||
onMounted(() => {
|
||||
obtainArticleInfo(Route.query.id)
|
||||
});
|
||||
|
||||
const obtainArticleInfo = (id) => {
|
||||
getArticleDetail(id).then(res => {
|
||||
articleDetail.value = res.data;
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.index-carousel {
|
||||
background-image: url('@/assets/images/index_carousel.png');
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.article-wrap {
|
||||
span {
|
||||
line-height: 1;
|
||||
box-shadow: 0 0 5px var(--el-color-primary-light-7);
|
||||
|
||||
&.active {
|
||||
background-image: linear-gradient(to right, var(--el-color-primary-light-5), var(--el-color-primary));
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-image: linear-gradient(to right, var(--el-color-primary-light-5), var(--el-color-primary));
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tow-line-overflow {
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.text-color {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.custom-tabs-label span {
|
||||
font-size: 20px;
|
||||
padding: 0px 10px;
|
||||
}
|
||||
</style>
|
||||
@ -1,160 +0,0 @@
|
||||
<template>
|
||||
<div class="w-full main-container pt-5">
|
||||
<el-carousel height="350px" indicator-position="none" arrow="never">
|
||||
<el-carousel-item>
|
||||
<div class="h-full index-carousel"></div>
|
||||
</el-carousel-item>
|
||||
</el-carousel>
|
||||
<div class="mt-[20px] mb-[50px]">
|
||||
<div>
|
||||
<div class="w-full">
|
||||
<el-breadcrumb :separator-icon="ArrowRight">
|
||||
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item :to="{ path: '/cms/article/list' }">文章</el-breadcrumb-item>
|
||||
<el-breadcrumb-item v-if="selectedCategoryName">{{ selectedCategoryName }}</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<div class="flex mt-[20px] items-start">
|
||||
<div class="w-[50px]">类目:</div>
|
||||
<el-row>
|
||||
<el-button class="mb-[10px]" @click="selectedCategory(categoryItem)" v-for="(categoryItem, categoryIndex) in activeCategoryLsit" :key="categoryIndex">{{ categoryItem.name }}</el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="article-list mb-[20px] cursor-pointer" v-for="(activeItem, activeIndex) in articleTableData.data" :key="activeIndex" @click="toLink(activeItem.id)">
|
||||
<div class="flex justify-between relative py-[20px] border-b-1 border-gray-300 border-solid">
|
||||
<div class="w-[150px] h-[150px] flex items-center">
|
||||
<img :src="img(activeItem.image)" />
|
||||
</div>
|
||||
<div class="w-[1030px]">
|
||||
<p class="text-xl font-bold">{{ activeItem.title }}</p>
|
||||
<span class="overflow-ellipsis mt-2 mb-2 tow-line-overflow text-gray-500">{{ activeItem.intro }}</span>
|
||||
</div>
|
||||
<!-- <div class="activeBo flex items-right mt-2 justify-end absolute">
|
||||
<span class="mr-5 text-sm text-gray-500">{{ activeItem.create_time }}</span>
|
||||
<div class="mr-3 flex items-center text-gray-500 text-sm"><el-icon><View /></el-icon> <span class="ml-1">158</span></div>
|
||||
<div class="mr-3 flex items-center text-gray-500 text-sm"><el-icon><Pointer /></el-icon> <span class="ml-1">22</span></div>
|
||||
<div class="mr-3 flex items-center text-gray-500 text-sm"><el-icon><Star /></el-icon> <span class="ml-1">55</span></div>
|
||||
<div class="flex items-center text-gray-500 text-sm"><el-icon><ChatDotRound /></el-icon> <span class="ml-1">655</span></div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<el-pagination class="justify-center" @current-change="handleCurrentChange"
|
||||
@size-change="handleSizeChange" :page-size="articleTableData.limit" background
|
||||
layout="prev, pager, next" :total="articleTableData.total" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { getArticleCategory, getArticleList } from '@/cms/api/article'
|
||||
import { ArrowRight } from '@element-plus/icons-vue'
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const router = useRouter();
|
||||
const activeCategoryLsit = ref([])
|
||||
const selectedCategoryName = ref()
|
||||
const articleTableData = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam: {
|
||||
title: '',
|
||||
category_id: ''
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取文章列表
|
||||
*/
|
||||
const loadArticleList = (page: number = 1) => {
|
||||
articleTableData.loading = true
|
||||
articleTableData.page = page
|
||||
|
||||
getArticleList({
|
||||
page: articleTableData.page,
|
||||
limit: articleTableData.limit,
|
||||
...articleTableData.searchParam
|
||||
}).then(res => {
|
||||
articleTableData.loading = false
|
||||
articleTableData.data = res.data.data
|
||||
articleTableData.total = res.data.total
|
||||
}).catch(() => {
|
||||
articleTableData.loading = false
|
||||
})
|
||||
}
|
||||
loadArticleList()
|
||||
|
||||
const checkArticleCategory = () => {
|
||||
getArticleCategory().then(res => {
|
||||
activeCategoryLsit.value = res.data.data;
|
||||
})
|
||||
}
|
||||
checkArticleCategory()
|
||||
|
||||
const selectedCategory = (item) => {
|
||||
articleTableData.searchParam.category_id = item.category_id;
|
||||
selectedCategoryName.value = item.name
|
||||
}
|
||||
|
||||
const handleSizeChange = (val: number) => {
|
||||
loadArticleList(val)
|
||||
}
|
||||
const handleCurrentChange = (val: number) => {
|
||||
loadArticleList(val)
|
||||
}
|
||||
const toLink = (id) => {
|
||||
router.push(`/cms/article/detail?id=${id}`)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.index-carousel {
|
||||
background-image: url('@/assets/images/index_carousel.png');
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.article-wrap {
|
||||
span {
|
||||
line-height: 1;
|
||||
box-shadow: 0 0 5px var(--el-color-primary-light-7);
|
||||
|
||||
&.active {
|
||||
background-image: linear-gradient(to right, var(--el-color-primary-light-5), var(--el-color-primary));
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-image: linear-gradient(to right, var(--el-color-primary-light-5), var(--el-color-primary));
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tow-line-overflow {
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.text-color {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.custom-tabs-label span {
|
||||
font-size: 20px;
|
||||
padding: 0px 10px;
|
||||
}
|
||||
|
||||
.activeBo {
|
||||
bottom: 20px;
|
||||
right: 0px
|
||||
}
|
||||
</style>
|
||||
@ -1,10 +0,0 @@
|
||||
export default [
|
||||
{
|
||||
path: "/cms/article/list",
|
||||
component: () => import('~/cms/pages/article/list.vue')
|
||||
},
|
||||
{
|
||||
path: "/cms/article/detail",
|
||||
component: () => import('~/cms/pages/article/detail.vue')
|
||||
}
|
||||
]
|
||||
@ -3,12 +3,12 @@
|
||||
return [
|
||||
'DIY_HELLO_WORLD_INDEX' => [
|
||||
'title' => get_lang('dict_diy.page_hello_world_index'),
|
||||
'page' => 'hello_world/pages/index',
|
||||
'page' => '/hello_world/pages/index',
|
||||
'action' => ''
|
||||
],
|
||||
'DIY_HELLO_WORLD_INFO' => [
|
||||
'title' => get_lang('dict_diy.page_hello_world_info'),
|
||||
'page' => 'hello_world/pages/info',
|
||||
'page' => '/hello_world/pages/info',
|
||||
'action' => ''
|
||||
],
|
||||
];
|
||||
@ -2,6 +2,7 @@
|
||||
return [
|
||||
//充值成功通知,站点端发送
|
||||
'recharge_success' => [
|
||||
'addon' => 'hello_world',
|
||||
'key' => 'recharge_success',
|
||||
'receiver_type' => 1,
|
||||
'name' => '充值成功通知',
|
||||
|
||||
@ -2,5 +2,5 @@ CREATE TABLE IF NOT EXISTS `{{prefix}}hello_world` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) NOT NULL DEFAULT '' COMMENT '名称',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='演示插件表';
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT='演示插件表';
|
||||
INSERT INTO `{{prefix}}hello_world`(`name`) VALUES ('名称');
|
||||
@ -2,13 +2,13 @@
|
||||
<view>
|
||||
hello-index,固定模板示例,我也可以装修
|
||||
<!-- 自定义模板渲染 -->
|
||||
<diy-group :data="props.data" :pullDownRefresh="props.pullDownRefresh"></diy-group>
|
||||
<diy-group :data="props.data" :pullDownRefreshCount="props.pullDownRefreshCount"></diy-group>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, watch } from 'vue';
|
||||
const props = defineProps(['data', 'pullDownRefresh']);
|
||||
const props = defineProps(['data', 'pullDownRefreshCount']);
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addon\recharge;
|
||||
|
||||
|
||||
/**
|
||||
* 插件安装之后单独的插件方法
|
||||
* Class Manage
|
||||
* @package addon\recharge
|
||||
*/
|
||||
class Manage
|
||||
{
|
||||
/**
|
||||
* 插件安装执行
|
||||
*/
|
||||
public function install()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件卸载执行
|
||||
*/
|
||||
public function uninstall()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件升级执行
|
||||
*/
|
||||
public function upgrade()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/***************************************************** 充值订单 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取充值订单列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getRechargeOrderList(params: Record<string, any>) {
|
||||
return request.get(`recharge/order`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取充值订单统计
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getRechargeStat(params: Record<string, any>) {
|
||||
return request.get(`recharge/order/stat`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取充值订单详情
|
||||
* @param order_id
|
||||
* @returns
|
||||
*/
|
||||
export function getRechargeOrderInfo(order_id: number) {
|
||||
return request.get(`recharge/order/${order_id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取充值订单状态列表
|
||||
* @returns
|
||||
*/
|
||||
export function getRechargeOrderStatusList() {
|
||||
return request.get(`recharge/order/status`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取退款记录
|
||||
* @returns
|
||||
*/
|
||||
export function getRechargeRefund(params: Record<string, any>) {
|
||||
return request.get(`recharge/refund`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取退款状态
|
||||
* @returns
|
||||
*/
|
||||
export function getRechargeRefundStatus() {
|
||||
return request.get(`recharge/refund/status`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 充值订单发起退款
|
||||
* @returns
|
||||
*/
|
||||
export function rechargeRefund(order_id: number) {
|
||||
return request.put(`recharge/refund/${order_id}`, {}, {showSuccessMessage: true});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取退款统计
|
||||
* @returns
|
||||
*/
|
||||
export function getRechargeRefundStat() {
|
||||
return request.get(`recharge/refund/stat`);
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
{
|
||||
"orderInfo":"订单详情",
|
||||
"orderDiscountMoney":"优惠金额",
|
||||
"ip":"下单IP",
|
||||
"payTime":"支付时间",
|
||||
"remark":"商家留言",
|
||||
"memberMessage":"买家留言",
|
||||
"orderNo":"订单编号",
|
||||
"orderStatus":"订单状态",
|
||||
"orderNoPlaceholder":"请输入订单编号",
|
||||
"createTime":"创建时间",
|
||||
"rechargeMoney":"充值金额",
|
||||
"orderMoney":"订单金额",
|
||||
"member":"买家",
|
||||
"orderFromName":"订单来源",
|
||||
"payTypeName":"支付方式",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间"
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
{
|
||||
"totalRechargeRefundMoney":"充值退款(元)",
|
||||
"totalRechargeMoney":"充值金额(元)",
|
||||
"rechargeRefundMoney":"充值退款",
|
||||
"rechargeNo":"充值单号",
|
||||
"orderStatus":"订单状态",
|
||||
"rechargeNoPlaceholder":"请输入充值单号",
|
||||
"createTime":"充值时间",
|
||||
"rechargeMoney":"充值金额",
|
||||
"orderMoney":"订单金额",
|
||||
"member":"会员信息",
|
||||
"orderFromName":"订单来源",
|
||||
"payTypeName":"支付方式",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间",
|
||||
"namePlaceholder":"请选择",
|
||||
"refundBtn":"退款",
|
||||
"refundContent":"是否确认退款",
|
||||
"payTime": "支付时间",
|
||||
"refundStatus": "退款状态",
|
||||
"startMoney": "起始金额",
|
||||
"endMoney": "结束金额"
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
{
|
||||
"refundNumber":"退款单号",
|
||||
"userInfo":"用户信息",
|
||||
"sourceNumber":"来源单号",
|
||||
"refundAmount":"退款金额",
|
||||
"refundTime":"退款时间",
|
||||
"detail": "详情",
|
||||
"statusName": "状态",
|
||||
"memberInfo": "会员信息",
|
||||
"refundSource": "退款来源",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间",
|
||||
"refundStatus": "退款状态",
|
||||
"accumulateRefundMoney": "累计退款金额(元)",
|
||||
"haveRefundMoney": "退款中金额(元)",
|
||||
"refundSuccessMonry": "退款成功金额(元)",
|
||||
"refundFailMoney": "退款失败金额(元)",
|
||||
"memberInfoPlaceholder":"请输入会员编号/昵称/手机号",
|
||||
"refundNumberPlaceholder":"请输入退款单号",
|
||||
"orderNumber": "来源单号",
|
||||
"orderNumberPlaceholder": "请输入来源单号",
|
||||
"refundDetail": "退款详情",
|
||||
"nickname": "会员昵称"
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
{
|
||||
"orderInfo":"订单详情",
|
||||
"orderDiscountMoney":"优惠金额",
|
||||
"ip":"下单IP",
|
||||
"payTime":"支付时间",
|
||||
"remark":"商家留言",
|
||||
"memberMessage":"买家留言",
|
||||
"orderNo":"订单编号",
|
||||
"orderStatus":"订单状态",
|
||||
"orderNoPlaceholder":"请输入订单编号",
|
||||
"createTime":"创建时间",
|
||||
"rechargeMoney":"充值金额",
|
||||
"orderMoney":"订单金额",
|
||||
"member":"买家",
|
||||
"orderFromName":"订单来源",
|
||||
"payTypeName":"支付方式",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间"
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
{
|
||||
"totalRechargeRefundMoney":"充值退款(元)",
|
||||
"totalRechargeMoney":"充值金额(元)",
|
||||
"rechargeRefundMoney":"充值退款",
|
||||
"rechargeNo":"充值单号",
|
||||
"orderStatus":"订单状态",
|
||||
"rechargeNoPlaceholder":"请输入充值单号",
|
||||
"createTime":"充值时间",
|
||||
"rechargeMoney":"充值金额",
|
||||
"orderMoney":"订单金额",
|
||||
"member":"会员信息",
|
||||
"orderFromName":"订单来源",
|
||||
"payTypeName":"支付方式",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间",
|
||||
"namePlaceholder":"请选择",
|
||||
"refundBtn":"退款",
|
||||
"refundContent":"是否确认退款",
|
||||
"payTime": "支付时间",
|
||||
"refundStatus": "退款状态",
|
||||
"startMoney": "起始金额",
|
||||
"endMoney": "结束金额"
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
{
|
||||
"refundNumber":"退款单号",
|
||||
"userInfo":"用户信息",
|
||||
"sourceNumber":"来源单号",
|
||||
"refundAmount":"退款金额",
|
||||
"refundTime":"退款时间",
|
||||
"detail": "详情",
|
||||
"statusName": "状态",
|
||||
"memberInfo": "会员信息",
|
||||
"refundSource": "退款来源",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间",
|
||||
"refundStatus": "退款状态",
|
||||
"accumulateRefundMoney": "累计退款金额(元)",
|
||||
"haveRefundMoney": "退款中金额(元)",
|
||||
"refundSuccessMonry": "退款成功金额(元)",
|
||||
"refundFailMoney": "退款失败金额(元)",
|
||||
"memberInfoPlaceholder":"请输入会员编号/昵称/手机号",
|
||||
"refundNumberPlaceholder":"请输入退款单号",
|
||||
"orderNumber": "来源单号",
|
||||
"orderNumberPlaceholder": "请输入来源单号",
|
||||
"refundDetail": "退款详情",
|
||||
"nickname": "会员昵称"
|
||||
}
|
||||
@ -1,110 +0,0 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-form :model="formData" label-width="150px" ref="formRef" class="page-form" v-loading="loading">
|
||||
<el-card class="box-card !border-none relative" shadow="never" v-if="formData">
|
||||
<h3 class="panel-title">{{ t('orderInfo') }}</h3>
|
||||
|
||||
<el-form-item :label="t('orderNo')">
|
||||
<div class="input-width">{{ formData.order_no }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('orderMoney')">
|
||||
<div class="input-width">{{ formData.order_money }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('orderDiscountMoney')">
|
||||
<div class="input-width">{{ formData.order_discount_money }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('member')">
|
||||
<div class="input-width">
|
||||
<div class="flex flex flex-col cursor-pointer" @click="toMember(formData.member_id)">
|
||||
<span class="">{{ formData.member.nickname || '' }}</span>
|
||||
<span class="">{{ formData.member.mobile || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('ip')">
|
||||
<div class="input-width">{{ formData.ip }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('orderFromName')">
|
||||
<div class="input-width">{{ formData.order_from_name }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('orderStatus')">
|
||||
<div class="input-width">{{ formData.order_status_info.name }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('payTypeName')">
|
||||
<div class="input-width">{{ formData.pay_type_name }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('createTime')">
|
||||
<div class="input-width">{{ formData.create_time || '' }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('payTime')">
|
||||
<div class="input-width">{{ formData.pay_time || '' }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('remark')">
|
||||
<div class="input-width">{{ formData.remark || '' }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('memberMessage')">
|
||||
<div class="input-width">{{ formData.member_message || '' }}</div>
|
||||
</el-form-item>
|
||||
|
||||
</el-card>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { getRechargeOrderInfo } from '@/recharge/api/recharge'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const orderId: number = parseInt(route.query.order_id)
|
||||
const loading = ref(true)
|
||||
|
||||
const formData: Record<string, any> | null = ref(null)
|
||||
|
||||
const setFormData = async (orderId: number = 0) => {
|
||||
loading.value = true
|
||||
formData.value = null
|
||||
await getRechargeOrderInfo(orderId)
|
||||
.then(({ data }) => {
|
||||
formData.value = data
|
||||
})
|
||||
.catch(() => {
|
||||
|
||||
})
|
||||
loading.value = false
|
||||
}
|
||||
if (orderId) setFormData(orderId)
|
||||
else loading.value = false
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const back = () => {
|
||||
router.push({ path: '/finance/recharge' })
|
||||
}
|
||||
/**
|
||||
* 会员详情
|
||||
*/
|
||||
const toMember = (memberId: number) => {
|
||||
router.push(`/member/detail?id=${memberId}`)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -1,280 +0,0 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<div class="flex justify-between items-center mb-[5px]">
|
||||
<span class="text-[20px]">{{pageName}}</span>
|
||||
</div>
|
||||
|
||||
<el-card class="box-card !border-none table-search-wra base-bg !px-[35px]" shadow="never">
|
||||
<el-row class="flex">
|
||||
<el-col :span="12" class="min-w-[100px]">
|
||||
<el-statistic :value="rechargeStatistics.recharge_money ? Number.parseFloat(rechargeStatistics.recharge_money).toFixed(2) : '0.00'">
|
||||
<template #title>
|
||||
<div class="text-[14px] mb-[9px]">{{ t('totalRechargeMoney') }}</div>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</el-col>
|
||||
<el-col :span="12" class="min-w-[100px]">
|
||||
<el-statistic :value="rechargeStatistics.recharge_refund_money ? Number.parseFloat(rechargeStatistics.recharge_refund_money).toFixed(2) : '0.00'">
|
||||
<template #title>
|
||||
<div class="text-[14px] mb-[9px]">{{ t('totalRechargeRefundMoney') }}</div>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="orderTableData.searchParam" ref="searchFormRef">
|
||||
<el-form-item :label="t('rechargeNo')" prop="order_no">
|
||||
<el-input v-model="orderTableData.searchParam.order_no" :placeholder="t('rechargeNoPlaceholder')" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('orderFromName')" prop="order_from">
|
||||
<el-select v-model="orderTableData.searchParam.order_from" clearable class="input-width">
|
||||
<el-option :label="t('selectPlaceholder')" value="" />
|
||||
<el-option :label="item" :value="key" v-for="(item, key) in channelList" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('orderStatus')" prop="order_status">
|
||||
<el-select v-model="orderTableData.searchParam.order_status" clearable class="input-width">
|
||||
<el-option :label="t('selectPlaceholder')" value="" />
|
||||
<el-option :label="item['name']" :value="item['status']" v-for="item in statusList" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('createTime')" prop="create_time">
|
||||
<el-date-picker v-model="orderTableData.searchParam.create_time" type="datetimerange" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('rechargeMoney')">
|
||||
<div class="region-input">
|
||||
<el-form-item prop="start_money">
|
||||
<input type="text" :placeholder="t('startMoney')" v-model="orderTableData.searchParam.start_money">
|
||||
</el-form-item>
|
||||
<span class="separator">-</span>
|
||||
<el-form-item prop="end_money">
|
||||
<input type="text" :placeholder="t('endMoney')" v-model="orderTableData.searchParam.end_money">
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('payTime')">
|
||||
<el-date-picker v-model="orderTableData.searchParam.pay_time" type="datetimerange" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadOrderList()">{{ t('search') }}</el-button>
|
||||
<el-button @click="searchFormRef?.resetFields()">{{ t('reset') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<div class="mt-[16px]">
|
||||
<el-table :data="orderTableData.data" size="large" v-loading="orderTableData.loading">
|
||||
<template #empty>
|
||||
<span>{{ !orderTableData.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
|
||||
<el-table-column :show-overflow-tooltip="true" :label="t('member')" align="left" min-width="140">
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center cursor-pointer " @click="toMember(row.member.member_id)">
|
||||
<img class="w-[50px] h-[50px] mr-[10px]" v-if="row.member.headimg" :src="img(row.member.headimg)" alt="">
|
||||
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/app/assets/images/default_headimg.png" alt="">
|
||||
<div class="flex flex flex-col">
|
||||
<span class="">{{ row.member.nickname || '' }}</span>
|
||||
<span class="">{{ row.member.mobile || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="order_no" :show-overflow-tooltip="true" :label="t('rechargeNo')" align="center" min-width="140" />
|
||||
|
||||
<el-table-column prop="order_money" :label="t('rechargeMoney')" align="center" min-width="140" />
|
||||
|
||||
<el-table-column prop="order_from_name" :label="t('orderFromName')" align="center" min-width="140" />
|
||||
|
||||
<el-table-column :label="t('orderStatus')" min-width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.order_status_info.name }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="pay_type_name" :label="t('payTypeName')" align="center" min-width="140" />
|
||||
|
||||
<el-table-column :label="t('createTime')" min-width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.create_time || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('payTime')" min-width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.pay_time || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('operation')" fixed="right" align="right" width="130">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button>
|
||||
|
||||
<el-button v-if="[1, 10].includes(row.order_status_info.status) && row.is_enable_refund && row.refund_status == 0" type="primary" link @click="refundFn(row)">{{ t('refundBtn') }}</el-button>
|
||||
|
||||
<template v-for="(item, index) in row.order_status_info.action">
|
||||
<el-button type="danger" link @click="orderEvent(row, item.class)">{{ item.name }}</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="orderTableData.page" v-model:page-size="orderTableData.limit"
|
||||
layout="total, sizes, prev, pager, next, jumper" :total="orderTableData.total"
|
||||
@size-change="loadOrderList()" @current-change="loadOrderList" />
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 是否退款 -->
|
||||
<el-dialog v-model="refundShowDialog" :title="t('refundBtn')" width="500px" :destroy-on-close="true">
|
||||
<p>{{ t('refundContent') }}</p>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="refundShowDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirmRefund" :loading="refundLoading">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getRechargeOrderStatusList, getRechargeOrderList, rechargeRefund, getRechargeStat } from '@/recharge/api/recharge'
|
||||
import { getChannelType } from '@/app/api/sys'
|
||||
import { img } from '@/utils/common'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { AnyObject } from '@/types/global'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const pageName = route.meta.title
|
||||
const memberId: number = parseInt(route.query.id || 0)
|
||||
|
||||
const channelList = ref([])
|
||||
const setChannelList = async () => {
|
||||
channelList.value = await (await getChannelType({})).data
|
||||
}
|
||||
setChannelList()
|
||||
|
||||
const orderTableData = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam: {
|
||||
order_no: '',
|
||||
order_status: '',
|
||||
member_id: memberId,
|
||||
create_time: [],
|
||||
pay_time: [],
|
||||
order_from: '',
|
||||
start_money: '',
|
||||
end_money: ''
|
||||
}
|
||||
})
|
||||
|
||||
const rechargeStatistics = ref([])
|
||||
const checkRechargeInfo = () => {
|
||||
getRechargeStat({
|
||||
member_id: memberId
|
||||
}).then(res => {
|
||||
rechargeStatistics.value = res.data
|
||||
})
|
||||
}
|
||||
checkRechargeInfo()
|
||||
|
||||
const statusList = ref([])
|
||||
|
||||
const searchFormRef = ref<FormInstance>()
|
||||
|
||||
const setCategoryList = async () => {
|
||||
statusList.value = await (await getRechargeOrderStatusList({})).data
|
||||
}
|
||||
setCategoryList()
|
||||
|
||||
const loadOrderList = (page: number = 1) => {
|
||||
orderTableData.loading = true
|
||||
orderTableData.page = page
|
||||
|
||||
getRechargeOrderList({
|
||||
page: orderTableData.page,
|
||||
limit: orderTableData.limit,
|
||||
...orderTableData.searchParam
|
||||
}).then(res => {
|
||||
orderTableData.loading = false
|
||||
orderTableData.data = res.data.data
|
||||
orderTableData.total = res.data.total
|
||||
}).catch(() => {
|
||||
orderTableData.loading = false
|
||||
})
|
||||
}
|
||||
loadOrderList()
|
||||
|
||||
/**
|
||||
* 订单详情
|
||||
* @param data
|
||||
*/
|
||||
const infoEvent = (data: any) => {
|
||||
router.push(`/order/recharge/detail?order_id=${data.order_id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单操作
|
||||
*/
|
||||
const orderEvent = (data: any, type: string) => {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款操作
|
||||
*/
|
||||
const refundShowDialog = ref(false)
|
||||
let refundData: AnyObject | null = null
|
||||
const refundLoading = ref(false)
|
||||
|
||||
const refundFn = (data: AnyObject) => {
|
||||
refundShowDialog.value = true
|
||||
refundData = data
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认退款
|
||||
*/
|
||||
const confirmRefund = () => {
|
||||
if (refundLoading.value) return
|
||||
refundLoading.value = true
|
||||
|
||||
rechargeRefund(refundData?.order_id).then(res => {
|
||||
refundShowDialog.value = false
|
||||
refundLoading.value = false
|
||||
}).catch(() => {
|
||||
refundLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员详情
|
||||
*/
|
||||
const toMember = (memberId: number) => {
|
||||
router.push(`/member/detail?id=${memberId}`)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -1,238 +0,0 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<div class="flex justify-between items-center mb-[5px]">
|
||||
<span class="text-[20px]">{{ pageName }}</span>
|
||||
</div>
|
||||
|
||||
<el-card class="box-card !border-none table-search-wra base-bg !px-[35px]" shadow="never">
|
||||
<el-row class="flex">
|
||||
<el-col :span="12">
|
||||
<div class="statistic-card">
|
||||
<el-statistic :value="refundStat.refund_all_money"></el-statistic>
|
||||
<div class="statistic-footer">
|
||||
<div class="footer-item text-[14px] text-[#666]">
|
||||
<span>{{ t('accumulateRefundMoney') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="statistic-card">
|
||||
<el-statistic :value="refundStat.refund_have_money"></el-statistic>
|
||||
<div class="statistic-footer">
|
||||
<div class="footer-item text-[14px] text-[#666]">
|
||||
<span>{{ t('haveRefundMoney') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="refundTableData.searchParam" ref="searchFormRef">
|
||||
<el-form-item :label="t('memberInfo')" prop="keywords">
|
||||
<el-input v-model="refundTableData.searchParam.keywords" class="w-[240px]" :placeholder="t('memberInfoPlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('refundNumber')" prop="refund_no">
|
||||
<el-input v-model="refundTableData.searchParam.refund_no" class="w-[240px]" :placeholder="t('refundNumberPlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('orderNumber')" prop="order_no">
|
||||
<el-input v-model="refundTableData.searchParam.order_no" class="w-[240px]" :placeholder="t('orderNumberPlaceholder')" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('refundStatus')" prop="status">
|
||||
<el-select v-model="refundTableData.searchParam.status" clearable class="input-width">
|
||||
<el-option :label="t('selectPlaceholder')" value="" />
|
||||
<el-option :label="item.name" :value="key" v-for="(item, key) in refundList" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('refundTime')" prop="create_time">
|
||||
<el-date-picker v-model="refundTableData.searchParam.create_time" type="datetimerange" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadRefundList()">{{ t('search') }}</el-button>
|
||||
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<div>
|
||||
<el-table :data="refundTableData.data" size="large" v-loading="refundTableData.loading">
|
||||
<template #empty>
|
||||
<span>{{ !refundTableData.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
|
||||
<el-table-column :show-overflow-tooltip="true" :label="t('memberInfo')" align="left" min-width="140">
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center cursor-pointer " @click="toMember(row.member.member_id)">
|
||||
<img class="w-[50px] h-[50px] mr-[10px]" v-if="row.member.headimg" :src="img(row.member.headimg)" alt="">
|
||||
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/app/assets/images/default_headimg.png" alt="">
|
||||
<div class="flex flex flex-col">
|
||||
<span class="">{{ row.member.nickname || '' }}</span>
|
||||
<span class="">{{ row.member.mobile || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="refund_no" :label="t('refundNumber')" align="center" min-width="200" />
|
||||
<el-table-column prop="item.item_name" :label="t('refundSource')" align="center" min-width="140" />
|
||||
<el-table-column prop="money" :label="t('refundAmount')" align="center" min-width="140" />
|
||||
<el-table-column :label="t('refundTime')" min-width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.create_time || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('statusName')" min-width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.status_name || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('operation')" fixed="right" align="right" width="130">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="refundTableData.page" v-model:page-size="refundTableData.limit"
|
||||
layout="total, sizes, prev, pager, next, jumper" :total="refundTableData.total"
|
||||
@size-change="loadRefundList()" @current-change="loadRefundList" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="refundInfoShowDialog" :title="t('refundDetail')" width="500px" :destroy-on-close="true">
|
||||
<el-form :model="refundInfo" label-width="120px" ref="formRef" :rules="formRules" class="page-form">
|
||||
<el-form-item :label="t('nickname')">
|
||||
<div class="input-width"> {{ refundInfo.member.nickname }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('refundSource')">
|
||||
<div class="input-width"> {{ refundInfo.item.item_name }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('refundAmount')">
|
||||
<div class="input-width"> {{ refundInfo.money }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('orderNumber')">
|
||||
<div class="input-width"> {{ refundInfo.item.order_no }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('refundNumber')">
|
||||
<div class="input-width"> {{ refundInfo.refund_no }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('refundTime')">
|
||||
<div class="input-width"> {{ refundInfo.create_time }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('statusName')">
|
||||
<div class="input-width"> {{ refundInfo.status_name }} </div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button type="primary" @click="refundInfoShowDialog = false">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { img } from '@/utils/common'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { getRechargeRefund, getRechargeRefundStatus, getRechargeRefundStat } from '@/recharge/api/recharge'
|
||||
import { FormInstance } from 'element-plus'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const pageName = route.meta.title
|
||||
const searchFormRef = ref<FormInstance>()
|
||||
const refundTableData = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam: {
|
||||
refund_no: '',
|
||||
// member_id,
|
||||
create_time: [],
|
||||
status: '',
|
||||
keywords: '',
|
||||
order_no: ''
|
||||
}
|
||||
})
|
||||
|
||||
const resetForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
|
||||
formEl.resetFields()
|
||||
loadRefundList()
|
||||
}
|
||||
/**
|
||||
* 获取退款列表
|
||||
*/
|
||||
const loadRefundList = (page: number = 1) => {
|
||||
refundTableData.loading = true
|
||||
refundTableData.page = page
|
||||
|
||||
getRechargeRefund({
|
||||
page: refundTableData.page,
|
||||
limit: refundTableData.limit,
|
||||
...refundTableData.searchParam
|
||||
}).then(res => {
|
||||
refundTableData.loading = false
|
||||
refundTableData.data = res.data.data
|
||||
refundTableData.total = res.data.total
|
||||
}).catch(() => {
|
||||
refundTableData.loading = false
|
||||
})
|
||||
}
|
||||
loadRefundList()
|
||||
|
||||
const refundList = ref([])
|
||||
const checkRefundList = () => {
|
||||
getRechargeRefundStatus().then(res => {
|
||||
refundList.value = res.data
|
||||
})
|
||||
}
|
||||
checkRefundList()
|
||||
|
||||
const refundStat = reactive({
|
||||
refund_all_money: 0.00,
|
||||
refund_have_money: 0.00,
|
||||
refund_Success_money: 0.00,
|
||||
refund_fail_moey: 0.00
|
||||
})
|
||||
const checkRefundStat = () => {
|
||||
getRechargeRefundStat().then(res => {
|
||||
refundStat.refund_all_money = res.data.all.money
|
||||
refundStat.refund_have_money = res.data.have.money
|
||||
refundStat.refund_Success_money = res.data['3'].money
|
||||
refundStat.refund_fail_moey = res.data['-1'].money
|
||||
})
|
||||
}
|
||||
checkRefundStat()
|
||||
|
||||
const refundInfoShowDialog = ref(false)
|
||||
const refundInfo = ref({})
|
||||
|
||||
const infoEvent = (info) => {
|
||||
refundInfo.value = info
|
||||
refundInfoShowDialog.value = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员详情
|
||||
*/
|
||||
const toMember = (memberId: number) => {
|
||||
router.push(`/member/detail?id=${memberId}`)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -1,119 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\recharge\app\adminapi\controller;
|
||||
|
||||
use addon\recharge\app\service\admin\RechargeOrderRefundService;
|
||||
use addon\recharge\app\service\admin\RechargeOrderService;
|
||||
use core\base\BaseAdminController;
|
||||
use think\Response;
|
||||
|
||||
class Order extends BaseAdminController
|
||||
{
|
||||
/**
|
||||
* 充值订单列表
|
||||
* @return Response
|
||||
*/
|
||||
public function lists()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ 'order_no', '' ],
|
||||
[ 'order_status', '' ],
|
||||
[ 'order_from', '' ],
|
||||
[ 'create_time', [] ],
|
||||
[ 'pay_time', [] ],
|
||||
[ 'member_id', '' ],
|
||||
[ 'start_money', 0 ],
|
||||
[ 'end_money', 0 ]
|
||||
]);
|
||||
return success(( new RechargeOrderService() )->getPage($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 充值订单详情
|
||||
* @param int $order_id
|
||||
* @return Response
|
||||
*/
|
||||
public function detail(int $order_id)
|
||||
{
|
||||
return success(( new RechargeOrderService() )->getDetail($order_id));
|
||||
}
|
||||
|
||||
public function status()
|
||||
{
|
||||
return success(( new RechargeOrderService() )->getStatus());
|
||||
}
|
||||
|
||||
public function refund($order_id)
|
||||
{
|
||||
$res = ( new RechargeOrderRefundService() )->create($order_id);
|
||||
if ($res === true) return success();
|
||||
return fail($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款列表
|
||||
* @return Response
|
||||
*/
|
||||
public function refundLists()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ 'create_time', [] ],
|
||||
[ 'member_id', '' ],
|
||||
[ 'refund_no', '' ],
|
||||
[ 'status', '' ],
|
||||
[ 'keywords', '' ],
|
||||
[ 'order_no', '' ],
|
||||
]);
|
||||
return success(( new RechargeOrderRefundService() )->getPage($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款详情
|
||||
* @param int $refund_id
|
||||
* @return Response
|
||||
*/
|
||||
public function refundDetail(int $refund_id)
|
||||
{
|
||||
return success(( new RechargeOrderRefundService() )->getDetail($refund_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询退款状态
|
||||
* @return Response
|
||||
*/
|
||||
public function refundStatus()
|
||||
{
|
||||
return success(( new RechargeOrderRefundService() )->getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款统计
|
||||
*/
|
||||
public function refundStat()
|
||||
{
|
||||
return success(( new RechargeOrderRefundService() )->stat());
|
||||
}
|
||||
|
||||
/**
|
||||
* 充值统计
|
||||
*/
|
||||
public function stat()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ 'member_id', '' ],
|
||||
]);
|
||||
$res = ( new RechargeOrderService() )->stat($data);
|
||||
return success($res);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
use app\adminapi\middleware\AdminCheckRole;
|
||||
use app\adminapi\middleware\AdminCheckToken;
|
||||
use app\adminapi\middleware\AdminLog;
|
||||
use think\facade\Route;
|
||||
|
||||
|
||||
/**
|
||||
* 订单相关路由
|
||||
*/
|
||||
Route::group('recharge', function() {
|
||||
|
||||
/***************************************************** 充值订单 *************************************************/
|
||||
//订单列表
|
||||
|
||||
Route::get('order', 'addon\recharge\app\adminapi\controller\Order@lists');
|
||||
|
||||
//订单详情
|
||||
Route::get('order/:order_id', 'addon\recharge\app\adminapi\controller\Order@detail');
|
||||
|
||||
//订单状态
|
||||
Route::get('order/status', 'addon\recharge\app\adminapi\controller\Order@status');
|
||||
|
||||
//订单统计
|
||||
Route::get('order/stat', 'addon\recharge\app\adminapi\controller\Order@stat');
|
||||
|
||||
// 订单发起退款
|
||||
Route::put('refund/:order_id', 'addon\recharge\app\adminapi\controller\Order@refund');
|
||||
|
||||
//退款订单列表
|
||||
Route::get('refund', 'addon\recharge\app\adminapi\controller\Order@refundLists');
|
||||
|
||||
//退款订单详情
|
||||
Route::get('refund/:refund_id', 'addon\recharge\app\adminapi\controller\Order@refundDetail');
|
||||
|
||||
//退款订单状态
|
||||
Route::get('refund/status', 'addon\recharge\app\adminapi\controller\Order@refundStatus');
|
||||
|
||||
//退款订单统计
|
||||
Route::get('refund/stat', 'addon\recharge\app\adminapi\controller\Order@refundStat');
|
||||
|
||||
})->middleware([
|
||||
AdminCheckToken::class,
|
||||
AdminCheckRole::class,
|
||||
AdminLog::class
|
||||
]);
|
||||
@ -1,53 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\recharge\app\api\controller;
|
||||
|
||||
use addon\recharge\app\service\api\RechargeOrderService;
|
||||
use core\base\BaseApiController;
|
||||
use think\Response;
|
||||
|
||||
class Recharge extends BaseApiController
|
||||
{
|
||||
/**
|
||||
* 充值订单创建
|
||||
* @return Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ 'member_message', '' ],
|
||||
[ 'recharge_money', 0 ]
|
||||
]);
|
||||
$res = ( new RechargeOrderService() )->recharge($data);
|
||||
return success($res);
|
||||
}
|
||||
|
||||
public function lists()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ 'order_status', '' ]
|
||||
]);
|
||||
$res = ( new RechargeOrderService() )->getPage($data);
|
||||
return success($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询充值订单详情
|
||||
* @param int $order_id
|
||||
* @return Response
|
||||
*/
|
||||
public function detail(int $order_id)
|
||||
{
|
||||
$res = ( new RechargeOrderService() )->getDetail($order_id);
|
||||
return success($res);
|
||||
}
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的saas管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud-admin.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
use app\api\middleware\ApiChannel;
|
||||
use app\api\middleware\ApiCheckToken;
|
||||
use app\api\middleware\ApiLog;
|
||||
use think\facade\Route;
|
||||
|
||||
|
||||
/**
|
||||
* 会员个人信息管理
|
||||
*/
|
||||
Route::group('recharge', function() {
|
||||
|
||||
/***************************************************** 充值订单相关 *************************************************/
|
||||
|
||||
//充值订单创建
|
||||
Route::post('recharge', 'addon\recharge\app\api\controller\Recharge@create');
|
||||
|
||||
// 充值订单列表
|
||||
Route::get('recharge', 'addon\recharge\app\api\controller\Recharge@lists');
|
||||
|
||||
// 充值订单详情
|
||||
Route::get('recharge/:order_id', 'addon\recharge\app\api\controller\Recharge@detail');
|
||||
|
||||
})->middleware(ApiChannel::class)
|
||||
->middleware(ApiCheckToken::class, true)
|
||||
->middleware(ApiLog::class);
|
||||
@ -1,132 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\recharge\app\dict;
|
||||
|
||||
use app\dict\pay\PayDict;
|
||||
|
||||
/**
|
||||
*充值订单相关枚举类
|
||||
* Class RechargeOrderDict
|
||||
* @package app\dict\order
|
||||
*/
|
||||
class RechargeOrderDict
|
||||
{
|
||||
//订单状态
|
||||
//待支付
|
||||
const WAIT_PAY = 0;
|
||||
//已完成
|
||||
const FINISH = 10;
|
||||
//已关闭
|
||||
const CLOSE = -1;
|
||||
|
||||
// 退款相关状态
|
||||
// 未申请
|
||||
const NOT_APPLAY = 0;
|
||||
// 退款中
|
||||
const REFUNDING = 1;
|
||||
// 退款完成
|
||||
const REFUND_COMPLETED = 2;
|
||||
// 退款失败
|
||||
const REFUND_FAIL = -1;
|
||||
|
||||
/**
|
||||
* 当前订单支持的支付方式
|
||||
*/
|
||||
const ALLOW_PAY = [
|
||||
PayDict::WECHATPAY,
|
||||
PayDict::ALIPAY,
|
||||
PayDict::OFFLINEPAY,
|
||||
];
|
||||
|
||||
/**
|
||||
* 订单类型以及名称
|
||||
* @return array
|
||||
*/
|
||||
public static function getOrderType()
|
||||
{
|
||||
return [
|
||||
'type' => 'recharge',
|
||||
'name' => get_lang('dict_order.order_type_recharge')
|
||||
];
|
||||
}
|
||||
|
||||
public static function getStatus($status = '')
|
||||
{
|
||||
$data = [
|
||||
|
||||
self::WAIT_PAY => [
|
||||
'name' => '待支付',
|
||||
'status' => self::WAIT_PAY,
|
||||
'is_refund' => 0,
|
||||
'action' => [],
|
||||
'member_action' => [
|
||||
[
|
||||
'name' => '支付',
|
||||
'class' => '',
|
||||
'params' => ''
|
||||
],
|
||||
],
|
||||
],
|
||||
self::FINISH => [
|
||||
'name' => '已完成',
|
||||
'status' => self::FINISH,
|
||||
'is_refund' => 0,
|
||||
'action' => [],
|
||||
'member_action' => [
|
||||
],
|
||||
],
|
||||
self::CLOSE => [
|
||||
'name' => '已关闭',
|
||||
'status' => self::CLOSE,
|
||||
'is_refund' => 0,
|
||||
'action' => [],
|
||||
'member_action' => [
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
];
|
||||
if ($status == '') {
|
||||
return $data;
|
||||
}
|
||||
return $data[$status] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取退款状态
|
||||
* @param string $status
|
||||
* @return array|array[]|string
|
||||
*/
|
||||
public static function getRefundStatus(string $status = '')
|
||||
{
|
||||
$data = [
|
||||
self::REFUNDING => [
|
||||
'name' => get_lang('dict_order_refund.refunding'),
|
||||
'status' => self::REFUNDING
|
||||
],
|
||||
self::REFUND_COMPLETED => [
|
||||
'name' => get_lang('dict_order_refund.refund_complete'),
|
||||
'status' => self::REFUND_COMPLETED
|
||||
],
|
||||
self::REFUND_FAIL => [
|
||||
'name' => get_lang('dict_order_refund.refund_fail'),
|
||||
'status' => self::REFUND_FAIL
|
||||
]
|
||||
];
|
||||
|
||||
if ($status == '') {
|
||||
return $data;
|
||||
}
|
||||
return $data[$status] ?? '';
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'RECHARGE_LINK' => [
|
||||
'key' => 'recharge',
|
||||
'addon_title' => get_lang('dict_diy.recharge_title'),
|
||||
'title' => get_lang('dict_diy.recharge_link'),
|
||||
'child_list' => [
|
||||
[
|
||||
'name' => 'RECHARGE_INDEX',
|
||||
'title' => get_lang('dict_diy.recharge_index'),
|
||||
'url' => '/recharge/pages/recharge',
|
||||
'is_share' => 1,
|
||||
'action' => ''
|
||||
]
|
||||
]
|
||||
],
|
||||
];
|
||||
@ -1,38 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\recharge\app\dict\member;
|
||||
|
||||
use core\dict\DictLoader;
|
||||
|
||||
/**
|
||||
* 会员账户变动类型
|
||||
* Class MemberAccountTypeDict
|
||||
* @package app\dict\member
|
||||
*/
|
||||
class MemberAccountChangeTypeDict
|
||||
{
|
||||
|
||||
/**
|
||||
* 获取账户变动方式
|
||||
* @param string $type
|
||||
* @return array|mixed|string
|
||||
*/
|
||||
public static function getType($type = '')
|
||||
{
|
||||
$account_change_type = (new DictLoader("MemberAccountChangeType"))->load();
|
||||
if (empty($type)) {
|
||||
return $account_change_type;
|
||||
}
|
||||
return $account_change_type[$type] ?? '';
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\recharge\app\dict\member;
|
||||
|
||||
|
||||
/**
|
||||
* 会员账户类型
|
||||
* Class MemberAccountTypeDict
|
||||
* @package app\dict\member
|
||||
*/
|
||||
class MemberAccountTypeDict
|
||||
{
|
||||
//会员积分
|
||||
public const POINT = 'point';
|
||||
//会员余额
|
||||
public const BALANCE = 'balance';
|
||||
|
||||
public static function getType($type = '')
|
||||
{
|
||||
$data = [
|
||||
self::POINT => get_lang('dict_member.account_point'),
|
||||
self::BALANCE => get_lang('dict_member.account_balance'),
|
||||
];
|
||||
if (empty($type)) {
|
||||
return $data;
|
||||
}
|
||||
return $data[$type] ?? '';
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
use addon\recharge\app\dict\member\MemberAccountTypeDict;
|
||||
|
||||
return [
|
||||
MemberAccountTypeDict::POINT => [
|
||||
//充值赠送
|
||||
'recharge_give' => [
|
||||
//名称
|
||||
'name' => get_lang('dict_member.account_point_recharge_give'),
|
||||
//是否增加
|
||||
'inc' => 1,
|
||||
//是否减少
|
||||
'dec' => 0,
|
||||
],
|
||||
],
|
||||
MemberAccountTypeDict::BALANCE => [
|
||||
|
||||
//充值
|
||||
'recharge' => [
|
||||
//名称
|
||||
'name' => get_lang('dict_member.account_balance_recharge'),
|
||||
//是否增加
|
||||
'inc' => 1,
|
||||
//是否减少
|
||||
'dec' => 0,
|
||||
],
|
||||
'recharge_refund' => [
|
||||
//名称
|
||||
'name' => get_lang('dict_member.account_balance_recharge_refund'),
|
||||
//是否增加
|
||||
'inc' => 0,
|
||||
//是否减少
|
||||
'dec' => 1,
|
||||
],
|
||||
]
|
||||
];
|
||||
@ -1,104 +0,0 @@
|
||||
<?php
|
||||
|
||||
return
|
||||
[
|
||||
[
|
||||
'menu_name' => '会员充值',
|
||||
'menu_key' => 'recharge',
|
||||
'menu_type' => 0,
|
||||
'icon' => 'element-Help',
|
||||
'api_url' => '',
|
||||
'router_path' => 'recharge',
|
||||
'view_path' => '',
|
||||
'methods' => '',
|
||||
'sort' => 100,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
'children' => [
|
||||
[
|
||||
'menu_name' => '充值订单',
|
||||
'menu_key' => 'recharge_order',
|
||||
'menu_type' => 0,
|
||||
'icon' => 'iconfont-iconchongzhidingdan',
|
||||
'api_url' => '',
|
||||
'router_path' => 'order',
|
||||
'view_path' => '',
|
||||
'methods' => 'get',
|
||||
'sort' => 100,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
'children' => [
|
||||
[
|
||||
'menu_name' => '订单列表',
|
||||
'menu_key' => 'recharge_order_list',
|
||||
'menu_type' => 1,
|
||||
'icon' => '',
|
||||
'api_url' => 'recharge/order',
|
||||
'router_path' => 'list',
|
||||
'view_path' => 'order/list',
|
||||
'methods' => 'get',
|
||||
'sort' => 100,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
'children' => [
|
||||
[
|
||||
'menu_name' => '退款',
|
||||
'menu_key' => 'recharge_order_refund',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'recharge/refund/<order_id>',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'put',
|
||||
'sort' => 100,
|
||||
'status' => 1,
|
||||
'is_show' => 0,
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
'menu_name' => '订单详情',
|
||||
'menu_key' => 'recharge_order_detail',
|
||||
'menu_type' => 1,
|
||||
'icon' => '',
|
||||
'api_url' => 'recharge/order/<order_id>',
|
||||
'router_path' => 'detail',
|
||||
'view_path' => 'order/detail',
|
||||
'methods' => 'get',
|
||||
'sort' => 90,
|
||||
'status' => 1,
|
||||
'is_show' => 0,
|
||||
],
|
||||
[
|
||||
'menu_name' => '退款记录',
|
||||
'menu_key' => 'recharge_order_refund_list',
|
||||
'menu_type' => 1,
|
||||
'icon' => 'iconfont-icontuikuanjilu',
|
||||
'api_url' => 'recharge/refund',
|
||||
'router_path' => 'refund',
|
||||
'view_path' => 'order/refund',
|
||||
'methods' => 'get',
|
||||
'sort' => 90,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
'children' => [
|
||||
[
|
||||
'menu_name' => '退款详情',
|
||||
'menu_key' => 'recharge_refund_detail',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'recharge/refund/<refund_id>',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'get',
|
||||
'sort' => 100,
|
||||
'status' => 1,
|
||||
'is_show' => 0,
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
@ -1,18 +0,0 @@
|
||||
<?php
|
||||
return [
|
||||
//充值成功通知,站点端发送
|
||||
'recharge_success' => [
|
||||
'key' => 'recharge_success',
|
||||
'receiver_type' => 1,
|
||||
'name' => '充值成功通知',
|
||||
'title' => '会员充值成功后发送',
|
||||
'async' => true,
|
||||
'variable' => [
|
||||
'price' => '充值金额',
|
||||
'balance' => '充值后账户',
|
||||
'time' => '充值时间',
|
||||
'trade_no' => '交易单号'
|
||||
],
|
||||
]
|
||||
|
||||
];
|
||||
@ -1,7 +0,0 @@
|
||||
<?php
|
||||
return [
|
||||
'recharge_success' => [
|
||||
'content' => '您充值金额¥{price}, 充值后金额¥{balance}',
|
||||
]
|
||||
|
||||
];
|
||||
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
return [
|
||||
'recharge_success' => [
|
||||
'tid' => '755',
|
||||
'content' => [
|
||||
['交易单号', '{trade_no}', 'keyword1'],
|
||||
['充值金额', '{price}', 'keyword2'],
|
||||
['账户余额', '{balance}', 'keyword3'],
|
||||
['充值时间', '{time}', 'keyword4'],
|
||||
],
|
||||
'kid_list' => [1, 3, 4, 2],
|
||||
'scene_desc' => ''
|
||||
]
|
||||
];
|
||||
@ -1,11 +0,0 @@
|
||||
<?php
|
||||
return [
|
||||
'recharge_success' => [
|
||||
'temp_key' => '52552',
|
||||
'keyword_name_list' => [ '充值时间', '充值金额' ],
|
||||
'content' => [
|
||||
[ '充值时间', '{time}', 'time1' ],
|
||||
[ '充值金额', '{price}', 'amount3' ],
|
||||
]
|
||||
]
|
||||
];
|
||||
@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
//文件执行序列号
|
||||
'bind' => [
|
||||
],
|
||||
'listen' => [
|
||||
//会员账户变化事件
|
||||
'MemberAccount' => [ 'addon\recharge\app\listener\member\MemberAccountListener' ],
|
||||
/**
|
||||
* 支付相关事件
|
||||
*/
|
||||
'PayCreate' => [ 'addon\recharge\app\listener\pay\PayCreateListener' ],
|
||||
//支付成功
|
||||
'PaySuccess' => [ 'addon\recharge\app\listener\pay\PaySuccessListener' ],
|
||||
//退款成功
|
||||
'RefundSuccess' => [ 'addon\recharge\app\listener\pay\RefundSuccessListener' ],
|
||||
//消息模板数据内容
|
||||
'NoticeData' => [
|
||||
'addon\recharge\app\listener\notice_template\RechargeSuccess',
|
||||
],
|
||||
'AllowPayTypeByTrade' => [
|
||||
'addon\recharge\app\listener\pay\PayTypeByTrade',
|
||||
],
|
||||
'WapIndex' => [ 'addon\recharge\app\listener\WapIndexListener' ],
|
||||
],
|
||||
'subscribe' => [
|
||||
],
|
||||
];
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
|
||||
];
|
||||
@ -1,34 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
'dict_member' => [
|
||||
'account_point_recharge_give' => 'recharge give',
|
||||
'account_balance_recharge' => 'recharge',
|
||||
|
||||
],
|
||||
'dict_order' => [
|
||||
//订单类型
|
||||
'order_type_recharge' => 'recharge order',
|
||||
|
||||
],
|
||||
|
||||
|
||||
'dict_menu_admin' => [
|
||||
'order' => 'order',
|
||||
'recharge_order' => 'recharge order',
|
||||
'recharge_order_list' => 'order list',
|
||||
'recharge_refund' => 'refund',
|
||||
'recharge_order_detail' => 'order detail',
|
||||
'recharge_refund_list' => 'refund list',
|
||||
'recharge_refund_detail' => 'refund detail',
|
||||
],
|
||||
];
|
||||
@ -1,13 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
];
|
||||
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
|
||||
];
|
||||
@ -1,33 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
|
||||
'dict_member' => [
|
||||
'account_point' => '积分',
|
||||
'account_balance' => '余额',
|
||||
'account_balance_recharge_refund' => '充值订单退款',
|
||||
'account_balance_recharge' => '余额充值',
|
||||
'account_point_recharge_give' => '充值赠送'
|
||||
],
|
||||
'dict_order' => [
|
||||
'trade_type_recharge' => '充值订单'
|
||||
],
|
||||
'dict_wap_index' => [
|
||||
'recharge' => '会员充值',
|
||||
'recharge_desc' => '在线充值到会员账户',
|
||||
],
|
||||
'dict_diy' => [
|
||||
'recharge_link' => '充值链接',
|
||||
'recharge_title'=>'会员充值',
|
||||
'recharge_index' => '充值'
|
||||
]
|
||||
];
|
||||
@ -1,13 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
];
|
||||
@ -1,31 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\recharge\app\listener;
|
||||
|
||||
/**
|
||||
* 手机端首页加载事件
|
||||
*/
|
||||
class WapIndexListener
|
||||
{
|
||||
public function handle()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'key' => 'recharge',
|
||||
"title" => get_lang("dict_wap_index.recharge"),
|
||||
'desc' => get_lang("dict_wap_index.recharge_desc"),
|
||||
"url" => "/recharge/pages/recharge",
|
||||
'icon'=>'addon/recharge/icon.png'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace addon\recharge\app\listener\member;
|
||||
|
||||
/**
|
||||
* 会员账户变化事件(积分,余额,零钱)
|
||||
* Class MemberAccount
|
||||
* @package app\listener\member
|
||||
*/
|
||||
class MemberAccountListener
|
||||
{
|
||||
/**
|
||||
* 接收会员账户变化记录
|
||||
* @param array $account_log
|
||||
*/
|
||||
public function handle(array $account_log)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addon\recharge\app\listener\notice_template;
|
||||
|
||||
use addon\recharge\app\service\core\CoreRechargeOrderService;
|
||||
use app\listener\notice_template\BaseNoticeTemplate;
|
||||
use app\service\core\member\CoreMemberService;
|
||||
|
||||
class RechargeSuccess extends BaseNoticeTemplate
|
||||
{
|
||||
|
||||
private $key = 'recharge_success';
|
||||
|
||||
public function handle(array $params)
|
||||
{
|
||||
if ($this->key == $params['key']) {
|
||||
$data = $params['data'];
|
||||
$order_id = $data['order_id'];
|
||||
|
||||
$core_order_service = new CoreRechargeOrderService();
|
||||
$order = $core_order_service->orderInfo($order_id);
|
||||
if (!empty($order)) {
|
||||
$member = (new CoreMemberService())->getInfoByMemberId($order['member_id']);
|
||||
//通过订单id查询订单信息
|
||||
return $this->toReturn(
|
||||
[
|
||||
'__wechat_page' => '',//模板消息链接
|
||||
'__miniprogram' => '',//模板消息小程序
|
||||
'__weapp_page' => '',//小程序链接
|
||||
'balance' => $member['balance'],//充值后的余额
|
||||
'price' => $order['order_item_money'],//订单项总价
|
||||
'time' => $order['create_time'],//创建时间
|
||||
'trade_no' => $order['out_trade_no'],//交易流水号
|
||||
],
|
||||
[
|
||||
'member_id' => $order['member_id'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\recharge\app\listener\pay;
|
||||
|
||||
use addon\recharge\app\dict\RechargeOrderDict;
|
||||
use app\dict\pay\PayDict;
|
||||
use core\exception\CommonException;
|
||||
use addon\recharge\app\service\core\CoreRechargeOrderService;
|
||||
|
||||
/**
|
||||
* 支付单据创建事件
|
||||
*/
|
||||
class PayCreateListener
|
||||
{
|
||||
public function handle(array $params)
|
||||
{
|
||||
$trade_type = $params['trade_type'] ?? '';
|
||||
if ($trade_type == 'recharge') {
|
||||
$trade_id = $params['trade_id'];
|
||||
$order_info = (new CoreRechargeOrderService())->orderInfo($trade_id);
|
||||
if ($order_info['order_status'] != RechargeOrderDict::WAIT_PAY) throw new CommonException('ONLY_PAYING_CAN_PAY');
|
||||
//添加订单支付表
|
||||
return [
|
||||
'main_type' => PayDict::MEMBER,
|
||||
'main_id' => $order_info['member_id'],//买家id
|
||||
'money' => $order_info['order_money'],//订单金额
|
||||
'trade_type' => 'recharge',//业务类型
|
||||
'trade_id' => $trade_id,
|
||||
'body' => get_lang("dict_order.trade_type_recharge")
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\recharge\app\listener\pay;
|
||||
use addon\recharge\app\service\core\CoreRechargeOrderService;
|
||||
|
||||
|
||||
/**
|
||||
* 支付异步回调事件
|
||||
*/
|
||||
class PaySuccessListener
|
||||
{
|
||||
public function handle(array $pay_info)
|
||||
{
|
||||
$trade_type = $pay_info['trade_type'] ?? '';
|
||||
if ($trade_type == 'recharge') {
|
||||
(new CoreRechargeOrderService())->pay($pay_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\recharge\app\listener\pay;
|
||||
|
||||
|
||||
use app\dict\pay\PayDict;
|
||||
|
||||
/**
|
||||
* 支付异步回调事件
|
||||
*/
|
||||
class PayTypeByTrade
|
||||
{
|
||||
public function handle(array $pay_info)
|
||||
{
|
||||
$trade_type = $pay_info[ 'trade_type' ] ?? '';
|
||||
$pay_type_list = $pay_info[ 'pay_type_list' ] ?? '';
|
||||
//充值订单不支持余额支付
|
||||
if (!empty($pay_type_list) && $trade_type == 'recharge') {
|
||||
unset($pay_type_list[ PayDict::BALANCEPAY ]);
|
||||
}
|
||||
return $pay_type_list;
|
||||
}
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的多应用管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace addon\recharge\app\listener\pay;
|
||||
|
||||
use addon\recharge\app\service\core\CoreRechargeRefundService;
|
||||
|
||||
/**
|
||||
* 退款成功事件
|
||||
*/
|
||||
class RefundSuccessListener
|
||||
{
|
||||
public function handle(array $refund_info)
|
||||
{
|
||||
//交易单据处理
|
||||
$trade_type = $refund_info['trade_type'] ?? '';
|
||||
if ($trade_type == 'recharge') {
|
||||
(new CoreRechargeRefundService())->refundComplete($refund_info['refund_no']);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user