zsk 1 year ago
parent f0943410a6
commit 10eaf22595

@ -206,4 +206,7 @@ const getInit = ($data) => {
.g_family_dingding {
font-family: "DingTalk_JinBuTi_Regular";
}
div[aria-hidden="true"] {
display: none !important;
}
</style>

@ -0,0 +1,50 @@
import request from "../utils/request";
// 获取轮播列表
export function getCarouselListApi(page, limit = 10) {
return request({
url: `/admin/banner/${page}/${limit}`,
method: "get",
});
}
// 保存轮播
export function saveCarouselApi(data) {
return request({
url: `/admin/banner/save`,
method: "post",
data: { img: data.img,title: data.title,status: data.status }
});
}
// 删除轮播
export function deleteCarouselApi(id) {
return request({
url: `/admin/banner/remove/${id}`,
method: "delete",
});
}
// 修改轮播
export function updateCarouselApi(data) {
return request({
url: `/admin/banner/update`,
method: "put",
data
});
}
// 上传图片
export function uploadImageApi(file) {
const formData = new FormData();
formData.append('file', file);
return request({
url: '/admin/cms/upload',
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
});
}

@ -0,0 +1,50 @@
import request from "../utils/request";
// 获取内容列表
export function getContentListApi(page, limit = 10,classify) {
return request({
url: `/admin/cms/${page}/${limit}?classify=${classify}`,
method: "get",
});
}
// 新增内容
export function saveContentApi(data) {
return request({
url: `/admin/cms/save`,
method: "post",
data
});
}
// 更新内容
export function updateContentApi(data) {
return request({
url: `/admin/cms/update`,
method: "put",
data
});
}
// 删除内容
export function deleteContentApi(id) {
return request({
url: `/admin/cms/remove/${id}`,
method: "delete",
});
}
// 上传图片
export function uploadImageApi(file) {
const formData = new FormData();
formData.append('file', file);
return request({
url: '/admin/cms/upload',
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
});
}

@ -116,6 +116,9 @@ onMounted(() => {
case "message":
items.push(getItem(item.title, item.id, item.component, () => h(SketchOutlined)));
break;
case "content":
items.push(getItem(item.title, item.id, item.component, () => h(SettingOutlined)));
break;
case "ServiceMarket":
items.push(getItem(item.title, item.id, item.component, () => h(SketchOutlined)));

@ -52,9 +52,17 @@ const router = createRouter({
path: "/merchantManagement/message",
name: "message",
meta: {
title: '内容管理',
title: '轮播管理',
},
component: () => import("../views/message/index.vue")
},
{
path: "/merchantManagement/content",
name: "content",
meta: {
title: '内容管理',
},
component: () => import("../views/message/content.vue")
}
// ,{
// path: "/merchantManagement/record",

@ -63,7 +63,7 @@ export let mockMenuList = {
"createTime": "",
"updateTime": "",
"deleted": 0,
"title": "内容管理",
"title": "轮播管理",
"menuName": "message",
"parentName": "",
"path": "message",
@ -83,6 +83,33 @@ export let mockMenuList = {
"exportTag": 0,
"childrenList": []
},
{
"id": 5,
"creator": "",
"updator": "",
"createTime": "",
"updateTime": "",
"deleted": 0,
"title": "内容管理",
"menuName": "content",
"parentName": "",
"path": "content",
"component": "/merchantManagement/content.vue",
"visible": 0,
"perms": "",
"icon": "icon-houtaishouye",
"remark": "",
"parentId": "",
"tagNames": "queryTag,addTag,updateTag,deleteTag",
"idx": 10,
"queryTag": 0,
"addTag": 0,
"deleteTag": 0,
"updateTag": 0,
"importTag": 0,
"exportTag": 0,
"childrenList": []
},
{
"id": 1,

@ -8,8 +8,8 @@ import {
} from 'ant-design-vue';
import commonJS from './common.js';
const router = useRouter()
const baseURL = "http://a.matripe.com.cn/api_stock"; // 正式环境线上
const baseURL2 = "https://a.matripe.com.cn/api_stock"; // 正式环境线上
const baseURL = "http://192.168.1.3:8800"; // 正式环境线上
// const baseURL2 = "https://a.matripe.com.cn/api_stock"; // 正式环境线上
let protocol = location.protocol
let trueUrl = protocol == 'http:' ? baseURL : baseURL2
console.log(protocol);

@ -133,7 +133,7 @@
<a-input style="width: 100%" placeholder="请输入电话" v-model:value="modalInfo.form.username" />
</a-form-item>
<a-form-item label="密码" name="name">
<a-input style="width: 100%" placeholder="请输入密码" v-model:value="modalInfo.form.idcard" />
<a-input style="width: 100%" placeholder="请输入密码" v-model:value="modalInfo.form.password" />
</a-form-item>
<a-form-item label="备注" name="desp">
@ -156,7 +156,7 @@ import { Modal, message } from "ant-design-vue";
import { useRouter, useRoute } from "vue-router";
import { getUserListApi, updateUserStatusApi, addUserApi, delUserApi,updateUserApi } from "../../api/userList/userList";
import { DownloadOutlined } from "@ant-design/icons-vue";
import idCardPanel from "../components/upload/image.vue";
import passwordPanel from "../components/upload/image.vue";
/* #################### 初始化事件 #################### */
const router = useRouter(); //
@ -165,7 +165,7 @@ const commonJS = getCurrentInstance().appContext.app.config.globalProperties.G;
const speed = ref(0);
const showAdd = ref(0);
onMounted(() => {
// getTable();
getTable();
});
/**
* 搜索事件
@ -187,7 +187,7 @@ const modalInfo = ref({
form:{
name:"",
username:'',
idcard:'',
password:'',
description:''
}
})
@ -198,17 +198,17 @@ const submitForm = ()=>{
params = {
name:modalInfo.value.form.name,
username:modalInfo.value.form.username,
idcard:modalInfo.value.form.idcard,
password:modalInfo.value.form.password,
description:modalInfo.value.form.description,
password:'123456',
id:modalInfo.value.id
}
if (!commonJS.regular(modalInfo.value.form.username, 'tel')) {
message.warning('请输入正确的手机号')
return false
}
// if (!commonJS.regular(modalInfo.value.form.username, 'tel')) {
// message.warning('')
// return false
// }
if(modalInfo.value.id){
@ -238,7 +238,7 @@ const handleToForm = ($type, $data) => {
form:{
name:$data.name,
username:$data.username,
idcard:$data.idcard,
password:$data.password,
description:$data.description,
},
id:$data.id
@ -246,7 +246,7 @@ const handleToForm = ($type, $data) => {
// updateUserApi({
// description: "",
// idcard: "123123123123123123",
// password: "123123123123123123",
// name: "",
// username: "13214534564",
// password: 123456,
@ -309,7 +309,7 @@ const openAdd = () =>{
form:{
name:"",
username:'',
idcard:'',
password:'',
description:''
}
}
@ -339,8 +339,8 @@ const columns = ref([
},
{
title: "密码",
key: "idcard",
dataIndex: "idcard",
key: "password",
dataIndex: "password",
width: "200px",
ellipsis: true,
},

@ -1,661 +0,0 @@
<template>
<!--我的职位-->
<div class="p-manage-myJob">
<div class="m-select g_flex_row_between g_pt_16">
<div class="g_flex_row_start">
<div class="g_w_320 g-search-btn g_mr_16">
<a-input-search v-model:value="tableData.keyword" placeholder="请输入姓名" @search="searchList" @change="handleChangeSearch" allowClear />
</div>
</div>
<div>
<!-- <a-button type="primary" @click="openAdd" :icon="h(PlusOutlined)">新增用户</a-button> -->
<!-- <a-button type="" class="g_border_d g_ml_16" @click="handleToForm('add', { id: 0 })" :icon="h(DownloadOutlined)">导出模版</a-button> -->
<!--
<a-dropdown :trigger="['click']">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="goShareList"></a-menu-item>
<a-menu-item key="2" @click="handleToForm('add',{id:0})"></a-menu-item>
</a-menu>
</template>
<a-button>
新增职位
<DownOutlined style="zoom:.8" />
</a-button>
</a-dropdown> -->
</div>
</div>
<div class="m-table g_mt_20 antd-table">
<a-table sticky :columns="columns" :scroll="{x:1000}" :data-source="tableData.records" size="middle" :pagination="false" :loading="tableData.loading" class="g_clear_scroll" style="max-width: calc(100% - 0px)">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'job'">
<!-- @click="goDetail(record)" -->
<div class="btn g_fs_14 g_cursor_point g_mr_13 g_flex_row_start">
<div class="g_ell_1">{{ "" }}</div>
</div>
</template>
<template v-if="column.key === 'age'">
<div class="g_ell_1">{{ record.sex + " " + record.age }}</div>
</template>
<template v-if="column.key === 'price'">
<!-- <div v-html="record.price"></div> -->
</template>
<template v-if="column.key === 'status'">
<a-switch @change="(e) => handleStatus(e, record)" :checked="record.status == 1 ? true : false" checked-children="" un-checked-children="" />
</template>
<template v-if="column.key === 'state'">
<div class="g_flex_row_between">
<!-- <div
class="btn g_fs_14 g_mr_13"
:class="'g_c_main g_cursor_point'"
:style="{
cursor: !record.statusBool ? 'not-allowed' : '',
color: !record.statusBool ? '#d8d8d8' : '#1677ff',
}"
@click="handleApplication(record)"
>
报名
</div> -->
<div class="btn g_c_main g_fs_14 g_cursor_point g_mr_13" @click="handleViewDetail(record)"></div>
<div class="btn g_c_main g_fs_14 g_cursor_point" @click="handleToForm('edit', record)">编辑</div>
</div>
</template>
</template>
<!-- <template #summary class="fixed-obj">
<div style="width: 70vw" class="g_pb_16 g_pt_16">
<a-table-summary fixed="bottom"> </a-table-summary>
</div>
</template> -->
</a-table>
<div class="g_pb_16 g_pt_16 g_pageBottom" v-if="tableData.records.length > 0">
<a-pagination v-model:current="tableData.page" v-model:page-size="tableData.size" :total="tableData.total" :pageSize="tableData.size" :show-total="(total) => `${total}`" @change="handleModalPage" @showSizeChange="handleModalSize" :show-quick-jumper="tableData.total < tableData.size ? false : true" :showSizeChanger="tableData.total < tableData.size ? false : true" :hideOnSinglePage="false" />
</div>
</div>
<!-- <a-modal v-model:open="modalInfo.isShow"
:title="modalInfo.title"
width="640px"
centered
:destroyOnClose="true"
:forceRender="true"
>
<div class="g_pt_30 modal-box">
<a-form :model="modalInfo.form"
name="basic"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 18 }"
autocomplete="off"
style="width: 80%;"
class="g_ml_51"
>
<a-form-item label="职位要求标签" name="name" required>
<a-input style="width: 100%" placeholder="请输入职位要求标签" v-model:value="modalInfo.form.name" />
</a-form-item>
<a-form-item label="标签类型" name="typeClassify" required>
<a-select v-model:value="modalInfo.form.typeClassify"
:getPopupContainer="(triggerNode) => triggerNode.parentNode.parentNode"
placeholder="请选择职位分类"
@change="handleUpdateSelect"
>
<a-select-option v-for="item in typeClassifyList" :value="item.id" :title="item.id">{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="说明" name="desp">
<a-textarea :rows='6' style="width: 100%" placeholder="请输入职位说明" v-model:value="modalInfo.form.desp" />
</a-form-item>
</a-form>
</div>
<template #footer>
<a-button @click="modalInfo.isShow = false">关闭</a-button>
<a-button @click="submitForm" type="primary">确定</a-button>
</template>
</a-modal> -->
<a-modal destroyOnClose ref="modalRef" v-model:open="tableDetail.isShow" title="持股详情" width="1200px" :bodyStyle="{ 'border-radius': '4px'}">
<div class="g_pt_8 g_pb_16" style=" overflow-y: auto">
<div class="g_float_right">
<a href="//a.matripe.com.cn/api_stock/admin/user/stock/record/download">
<a-button class="g_mr_12">
<template #icon>
<DownloadOutlined />
</template>
导出模板
</a-button>
</a>
<a-upload :action="baseUrl + '/admin/user/stock/record/import'" :data="{userId}" accept=".xlsx, .xls, .xlsm, .xltx, .xltm" @change="getMoreInfo">
<a-button type="primary"><PlusOutlined />导入文件</a-button>
</a-upload>
</div>
<div class="g_float_none"></div>
<div class="g_mt_16 g_clear_scroll" style="max-height: calc(100vh - 464px); overflow-y: auto">
<a-table :columns="tableDetail.columns" :data-source="tableDetail.list" size="middle" :pagination="false">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'rank'">
<span>{{ record.rank }}</span>
</template>
</template>
</a-table>
</div>
<div class="g_mt_20">
<a-pagination v-model:current="tableDetail.page" v-model:page-size="tableDetail.size" :total="tableDetail.count" :pageSize="tableDetail.size" :show-total="(total) => `${total}`" @change="handleModalDetailPage" @showSizeChange="handleModalDetailSize" :show-quick-jumper="tableDetail.count < tableDetail.size ? false : true" :showSizeChanger="tableDetail.count < tableDetail.size ? false : true" :hideOnSinglePage="false" />
</div>
</div>
<template #footer>
<a-button @click="tableDetail.isShow = false" type="primary">确定</a-button>
</template>
</a-modal>
<a-modal v-model:open="showAdd" :title="modalInfo.title" style="width: 734px" :destroyOnClose="true">
<div class="g_pt_30 modal-box">
<a-form :model="modalInfo.form"
name="basic"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 18 }"
autocomplete="off"
style="width: 80%;"
class="g_ml_51"
>
<a-form-item label="姓名" name="name" required>
<span class="ant-form-text">{{modalInfo.form.name}}</span>
<!-- <a-input style="width: 100%" placeholder="请输入姓名" v-model:value="modalInfo.form.name" /> -->
<!-- <a-select ref="select" v-model:value="modalInfo.form.name" placeholder="请选择用户" @focus="focus" @change="handleChange">
<a-select-option v-for="item in userList" :value="item.id" :title="item.id">{{ item.name }}</a-select-option>
</a-select> -->
</a-form-item>
<a-form-item label="持股数" name="num" required>
<a-input style="width: 100%" placeholder="请输入持股数" v-model:value="modalInfo.form.num" />
</a-form-item>
<a-form-item label="持股比例" name="percent" required>
<a-input style="width: 100%" placeholder="请输入持股比例" v-model:value="modalInfo.form.percent" />
</a-form-item>
<a-form-item label="持股价值(元)" name="amount" required>
<a-input style="width: 100%" placeholder="请输入持股价值" v-model:value="modalInfo.form.amount" />
</a-form-item>
<!-- <a-form-item label="备注" name="desp">
<a-textarea :rows='6' style="width: 100%" placeholder="请输入备注" v-model:value="modalInfo.form.description" />
</a-form-item> -->
</a-form>
</div>
<template #footer>
<a-button @click="showAdd = false" >关闭</a-button>
<a-button @click="submitForm" type="primary">确定</a-button>
</template>
</a-modal>
</div>
</template>
<script setup>
import request from "../../utils/request"; //
import { ref, onMounted, getCurrentInstance, h, watch } from "vue";
import { PlusOutlined, EllipsisOutlined, UploadOutlined, DownOutlined } from "@ant-design/icons-vue";
import { Modal, message } from "ant-design-vue";
import { useRouter, useRoute } from "vue-router";
import { getUserListApi, updateUserStatusApi, addUserApi, delUserApi,updateUserStockApi,getStockUserListApi,addStockUserApi, getUserMoreListApi} from "../../api/userList/userList";
import { DownloadOutlined } from "@ant-design/icons-vue";
import idCardPanel from "../components/upload/image.vue";
/* #################### 初始化事件 #################### */
const router = useRouter(); //
const route = useRoute();
const commonJS = getCurrentInstance().appContext.app.config.globalProperties.G;
const speed = ref(0);
const showAdd = ref(0);
const userList = ref([]);
const userId = ref(0);
let baseUrl = ref(request.userCustom);
const handleChange = value => {
console.log(`selected ${value}`);
modalInfo.value.form.userId = value
};
onMounted(() => {
getTable();
});
const tableDetail = ref({
page: 1,
size: 50,
count: 0,
list: [],
speed: -1,
isShow: false,
keys: "",
columns: [],
pagination: {},
});
const handleViewDetail = (item) => {
//
tableDetail.value = {
page: 1,
size: 20,
limit: 20,
count: 0,
list: [],
speed: -1,
isShow: true,
keys: "",
columns: [],
pagination: {},
};
userId.value = item.userId
// itemData.value = {
// userId: item.id,
// agencyTeamId: item.agencyTeamId,
// };
getModalDetail();
};
const getModalDetail = () => {
tableDetail.value.columns = [
{
title: "序号",
key: "rank",
dataIndex: "rank",
width: "50px",
ellipsis: true,
},
{
title: "取得方式",
key: "sourceFrom",
dataIndex: "sourceFrom",
ellipsis: true,
minWidth: "100px",
},
{
title: "持股主体",
key: "name",
dataIndex: "name",
width: "240px",
ellipsis: true,
},
{
title: "持股数量",
key: "num",
dataIndex: "num",
width: "200px",
ellipsis: true,
},
];
getUserMoreList();
};
/**
* 搜索事件
*/
const searchList = (e) => {
console.log("searchList", e);
tableData.value.page = 1;
getTable();
};
/* #################### 顶部事件 #################### */
const handleChangeSearch = (e) => {
if (tableData.value.keyword == "") {
getTable();
}
};
const modalInfo = ref({
title:'新增个人数据',
id:0,
form:{
name:null,
num:'',
percent:'',
amount:'',
}
})
const submitForm = ()=>{
let url = '',params = {};
console.log(userList.value);
console.log(modalInfo.value.form.userId);
// let obj = userList.value.find(item => item.id === modalInfo.value.form.userId)
// console.log(obj);
params = {
name:modalInfo.value.form.name,
num:modalInfo.value.form.num,
percent:modalInfo.value.form.percent,
amount:modalInfo.value.form.amount,
userId:modalInfo.value.form.userId,
id:modalInfo.value.id
}
if(modalInfo.value.id){
delete params.password;
updateUserStockApi(params).then((res)=>{
showAdd.value = false;
message.success("修改成功");
getTable();
});
}else{
addStockUserApi(params).then((res)=>{
showAdd.value = false;
message.success("新增成功");
getTable();
});
}
}
const handleToForm = ($type, $data) => {
showAdd.value = true;
console.log($data.id);
modalInfo.value = {
isShow:true,
title:'修改个人数据',
form:{
name:$data.name,
num:$data.num,
percent:$data.percent,
amount:$data.amount,
userId:$data.userId
},
id:$data.id
}
// updateUserApi({
// description: "",
// idcard: "123123123123123123",
// name: "",
// username: "13214534564",
// password: 123456,
// status: 0,
// username: "",
// }).then(() => {
// message.success("");
// getTable();
// });
// if ($data.id > 0) {
// router.push({
// path: "/merchantManagement/jobForm",
// query: {
// id: $data.id ? $data.id : 0,
// type: $type,
// templateId: $data.templateId ? $data.templateId : 0,
// },
// });
// } else {
// router.push({
// path: "/merchantManagement/jobForm",
// query: {
// id: $data.id ? $data.id : 0,
// type: $type,
// },
// });
// }
};
/* #################### 表格事件 #################### */
const tableData = ref({
keyword: "",
page: 1,
limit: 20,
total: 0,
count: 0,
loading: false,
records: [],
jobType2Num: "-",
jobType1Num: "-",
});
const getTable = () => {
console.log(tableData.value);
tableData.value.loading = true;
getStockUserListApi({ limit: tableData.value.limit, page: tableData.value.page, keyword: tableData.value.keyword }).then((res) => {
console.log(res);
tableData.value = { ...res.data, keyword: tableData.value.keyword, page: res.data.current, limit: res.data.size };
tableData.value.records.forEach((item, index) => {
item.rank = index + 1;
});
});
};
const openAdd = () =>{
showAdd.value = true
modalInfo.value.id = 0;
modalInfo.value = {
title:"新增个人数据",
form:{
name:null,
username:'',
idcard:'',
description:''
}
}
getUserListApi({ limit:100, page: 1, keyword:""}).then((res)=>{
userList.value = res.data.records
// modalInfo.value.name = res.data.records[0].name
console.log(res);
});
};
const columns = ref([
{
title: "序号",
key: "rank",
dataIndex: "rank",
width: "50px",
ellipsis: true,
},
{
title: "姓名",
key: "name",
dataIndex: "name",
},
{
title: "持股数",
key: "num",
dataIndex: "num",
ellipsis: true,
width: "240px",
},
{
title: "持股比例",
key: "percent",
dataIndex: "percent",
width: "240px",
ellipsis: true,
customRender: (record) => {
return record.record.percent ? record.record.percent : '-';
},
},
{
title: "持股价值(元)",
key: "amount",
dataIndex: "amount",
ellipsis: true,
width: "240px",
},
{
title: "操作",
key: "state",
dataIndex: "state",
width: "90px",
ellipsis: true,
},
]);
/**
* 切换用户状态
*/
const handleStatus = (e, $data) => {
updateUserStatusApi({ id: $data.id, status: e ? 1 : 0 }).then(() => {
message.success("更新成功");
getTable();
});
};
const addInfo = ref({});
const goDetail = ($item) => {
console.log($item);
//
if ($item.jobType == 1) {
//
router.push({
path: "/merchantManagement/shareJobDetail",
query: {
id: $item.templateId,
shared: $item.shared,
form: "joblist",
},
});
} else {
//
router.push({
path: "/merchantManagement/jobDetail",
query: {
id: $item.id,
},
});
}
};
const handleApplication = (record) => {
console.log(record);
if (!record.statusBool) {
return false;
}
//
router.push({
path: "/merchantManagement/recordJob",
query: {
company: record.boss,
job: record.job,
jobId: record.id,
templateId: record.templateId,
jobType: record.jobType,
},
});
};
const handleDel = ($data) => {
commonJS.gConfirmModal(
"删除",
"确认删除该用户吗?",
() => {
delUserApi($data.id).then(() => {
message.success("删除成功");
getTable();
});
},
() => {}
);
};
/* #################### 分页器事件 #################### */
const handleModalPage = ($page, $size) => {
//
console.log($page);
console.log($size);
tableData.value.page = $page;
getTable();
};
const handleModalSize = ($page, $size) => {
// size
tableData.value.page = 1;
tableData.value.size = $size;
getTable();
};
/* #################### 分页器事件 #################### */
const handleModalDetailPage = ($page, $size) => {
//
console.log($page);
console.log($size);
tableDetail.value.page = $page;
getUserMoreList();
};
const handleModalDetailSize = ($page, $size) => {
// size
tableDetail.value.page = 1;
tableDetail.value.size = $size;
getUserMoreList();
};
/**
* 获取持股列表
*/
const getUserMoreList = () => {
getUserMoreListApi({ limit: tableDetail.value.limit, page: tableDetail.value.page, userId: userId.value }).then((res) => {
console.log(res);
// tableDetail.value = { ...res.data, keyword: tableData.value.keyword, page: res.data.current, limit: res.data.size };
tableDetail.value.list = res.data.records
tableDetail.value.count = res.data.total
tableDetail.value.list.forEach((item, index) => {
item.rank = index + 1;
});
// stockMoreList.value = res.data;
// stockMoreList.value.forEach((item, index) => {
// item.rank = index + 1;
// });
});
};
/**
* 上传持股文件
*/
const getMoreInfo = (info) => {
console.log(info);
if (info.file.response) {
if (info.file.response.code == 200) {
getUserMoreList();
message.success("操作成功");
}
}
};
</script>
<style lang="less">
.ant-table-cell:empty::before{
content: "-";
}
.p-manage-myJob {
position: relative;
min-height: calc(100vh - 213px);
width: 100%;
height: 100px;
.btn-active {
width: 40px;
height: 24px;
margin-left: 6.5px;
font-size: 12px;
color: #f6343e;
background-color: #fff3f3;
padding: 1px 3px;
zoom: 0.6;
margin-top: 8px;
text-align: center;
}
}
.ant-spin-blur .ant-empty {
opacity: 0;
}
</style>

@ -1,356 +0,0 @@
<template>
<div>
<div class="g_bg_f g_br_4">
<div class="g_pt_18 g_pl_24 g_pb_12 g_pr_24 g_fw_600 g_flex_row_between">
<div class="g_fw_600">基本信息</div>
<div>
<a-button type="primary" @click="editStatus = true">编辑</a-button>
</div>
</div>
<a-divider class="g_mt_0 g_mb_24" />
<div class="g_pl_24 g_pr_24 g_fs_14 g_pb_32" style="width: 630px">
<div class="g_flex_row_start flex_nr g_mb_20 g_w_all">
<div class="g_w_400">
<span class="g_c_6">主体</span>
<span>{{ showBaseInfo.name || "-" }}</span>
</div>
<div>
<span class="g_c_6">当前估值</span>
<span>{{ showBaseInfo.appraisement || "-" }}</span>
</div>
</div>
<div class="g_flex_row_start flex_nr g_w_all">
<div class="g_w_400">
<span class="g_c_6">当前总股本</span>
<span>{{ showBaseInfo.capitalStock || "-" }}</span>
</div>
<div>
<span class="g_c_6">每股价格</span>
<span>{{ showBaseInfo.unitPrice || "-" }}</span>
</div>
</div>
</div>
</div>
<a-modal v-model:open="editStatus" title="编辑信息" width="640px" centered :destroyOnClose="true" :forceRender="true">
<div class="g_pt_30 g_pb_10">
<a-form :model="baseInfo" ref="baseInfoForm" name="basic" autocomplete="off" @finish="submitBaseInfo" @change="showInfo" @validate="validateForm" :label-col="{ style: { width: '150px' } }" lab :wrapper-col="{ span: 15 }">
<a-form-item name="name" class="" :rules="[{ required: true, message: '请输入主体' }]">
<template #label>
<div class="g_c_6">主体</div>
</template>
<a-input placeholder="请输入主体" v-model:value="baseInfo.name" class="" />
</a-form-item>
<a-form-item name="appraisement" class=" " :rules="[{ required: true, message: '请输入当前估值' }]">
<template #label>
<div class="g_c_6">当前估值</div>
</template>
<a-input placeholder="请输入当前估值" v-model:value="baseInfo.appraisement" class="" />
</a-form-item>
<a-form-item name="capitalStock" class="" :rules="[{ required: true, message: '请输入当前总股本' }]">
<template #label>
<div class="g_c_6">当前总股本</div>
</template>
<a-input placeholder="请输入当前总股本" v-model:value="baseInfo.capitalStock" class="" />
</a-form-item>
<a-form-item name="unitPrice" class=" " :rules="[{ required: true, message: '请输入每股价格' }]">
<template #label>
<div class="g_c_6">每股价格</div>
</template>
<a-input placeholder="请输入每股价格" v-model:value="baseInfo.unitPrice" class="" />
</a-form-item>
</a-form>
</div>
<template #footer>
<a-button @click="noEdit"></a-button>
<a-button @click="singleSubmit" type="primary">确定</a-button>
</template>
</a-modal>
<div class="g_bg_f g_br_4 g_mt_16">
<div class="g_pt_18 g_pl_24 g_pr_24 g_pb_12 g_flex_row_between">
<div class="g_fw_600">股权结构</div>
<div>
<a href="//a.matripe.com.cn/api_stock/admin/stock/structure/download">
<a-button> <DownloadOutlined class="" />导出模版</a-button>
</a>
<a-upload :action="baseUrl + '/admin/stock/structure/import'" accept=".xlsx, .xls, .xlsm, .xltx, .xltm" @change="getFileInfo">
<a-button type="primary" class="g_ml_10"><PlusOutlined />导入文件</a-button>
</a-upload>
</div>
</div>
<a-divider class="g_mt_0 g_mb_20" />
<div class="g_flex_row_between g_pl_24 g_pr_24 g_pb_20">
<a-table :columns="columns" :data-source="stockInfoList" size="middle" :pagination="false" class="g_clear_scroll" :scroll="{ x: '' }">
<template #headerCell="{ column }">
<template v-if="column.key === 'name'">
<div class="g_fw_600">姓名</div>
</template>
</template>
</a-table>
</div>
</div>
<div class="g_bg_f g_br_4 g_mt_16">
<div class="g_pt_18 g_pl_24 g_pr_24 g_pb_12 g_flex_row_between">
<div class="g_fw_600">增资扩股变化</div>
<div>
<a href="//a.matripe.com.cn/api_stock/admin/stock/change/download">
<a-button> <DownloadOutlined class="" />导出模版</a-button>
</a>
<a-upload :action="baseUrl + '/admin/stock/change/import'" accept=".xlsx, .xls, .xlsm, .xltx, .xltm" @change="getMoreInfo">
<a-button type="primary" class="g_ml_10"><PlusOutlined />导入文件</a-button>
</a-upload>
</div>
</div>
<a-divider class="g_mt_0 g_mb_20" />
<div class="g_flex_row_between g_pl_24 g_pr_24 g_pb_20">
<a-table :columns="columns1" :data-source="stockMoreList" size="middle" :pagination="false" class="g_clear_scroll" :scroll="{ x: '' }">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'state'">
<div class="g_c_main">删除</div>
</template>
</template>
</a-table>
</div>
</div>
</div>
</template>
<script setup>
import request from "../../utils/request"; //
import { DownloadOutlined, PlusOutlined } from "@ant-design/icons-vue";
import { ref, onMounted, getCurrentInstance, watch, onBeforeUnmount } from "vue";
import { message } from "ant-design-vue";
import { getProjectInfoApi, updateProjectInfoApi, importStockModelApi, getStockInfoListApi, getStockMoreListApi } from "../../api/userList/porjectInfo";
const commonJS = getCurrentInstance().appContext.app.config.globalProperties.G;
import { useRouter, useRoute } from "vue-router";
const router = useRouter(); //
const route = useRoute();
import { useStore } from "@/stores/counter";
const storeJS = useStore();
onMounted(() => {
getProjectInfo();
getStockInfoList();
getStockMoreList();
});
const baseInfo = ref({});
const showBaseInfo = ref({});
const baseInfoForm = ref(null);
const editStatus = ref(false);
const stockInfoList = ref([]);
const stockMoreList = ref([]);
const submitBaseInfo = (e) => {
console.log(e);
};
const validateForm = (e) => {
console.log(e);
console.log(showBaseInfo.value);
};
const noEdit = (e) => {
editStatus.value = false;
baseInfo.value = JSON.parse(JSON.stringify(showBaseInfo.value));
};
let columns = ref([
{
title: "序号",
key: "rank",
dataIndex: "rank",
width: "50px",
ellipsis: true,
fixed: "left",
},
{
title: "姓名",
key: "name",
dataIndex: "name",
// width: "220px",
ellipsis: true,
fixed: "left",
},
{
title: "股数",
key: "num",
dataIndex: "num",
width: "300px",
// minWidth: 100,
ellipsis: true,
},
{
title: "百分比",
key: "percent",
dataIndex: "percent",
width: "300px",
// minWidth: 100,
ellipsis: true,
},
]);
let columns1 = ref([
{
title: "序号",
key: "rank",
dataIndex: "rank",
width: "50px",
ellipsis: true,
// fixed: "left",
},
{
title: "融资轮次",
key: "name",
dataIndex: "name",
// width: "220px",
ellipsis: true,
customRender: (record) => {
return record.record.name || "-";
},
// fixed: "left",
},
{
title: "股本数",
key: "capitalStock",
dataIndex: "capitalStock",
width: "100px",
customRender: (record) => {
return record.record.capitalStock || "-";
},
// minWidth: 100,
ellipsis: true,
},
{
title: "估值",
key: "appraisement",
dataIndex: "appraisement",
width: "100px",
customRender: (record) => {
return record.record.appraisement || "-";
},
// minWidth: 100,
ellipsis: true,
},
{
title: "股价",
key: "price",
dataIndex: "price",
width: "100px",
// minWidth: 100,
customRender: (record) => {
return record.record.price || "-";
},
ellipsis: true,
},
{
title: "增资金额",
key: "additionalShare",
dataIndex: "additionalShare",
width: "100px",
customRender: (record) => {
return record.record.additionalShare || "-";
},
// minWidth: 100,
ellipsis: true,
},
// {
// title: "",
// key: "state",
// dataIndex: "state",
// width: "60px",
// // minWidth: 100,
// ellipsis: true,
// },
]);
/**
* 获取股权结构列表
*/
const getStockInfoList = () => {
getStockInfoListApi().then((res) => {
console.log(res);
stockInfoList.value = res.data;
stockInfoList.value.forEach((item, index) => {
item.rank = index + 1;
});
});
};
/**
* 获取增资扩股列表
*/
const getStockMoreList = () => {
getStockMoreListApi().then((res) => {
console.log(res);
stockMoreList.value = res.data;
stockMoreList.value.forEach((item, index) => {
item.rank = index + 1;
});
});
};
const getProjectInfo = () => {
getProjectInfoApi().then((res) => {
console.log(res);
showBaseInfo.value = JSON.parse(JSON.stringify(res.data));
baseInfo.value = res.data;
});
};
const showInfo = (e) => {
console.log(e);
};
/**
* 表单提交事件
*/
const singleSubmit = () => {
baseInfoForm.value
.validate()
.then((value) => {
// console.log(value);
value.id = showBaseInfo.value.id;
updateProjectInfoApi(value).then((res) => {
// console.log(res);
message.success("修改成功");
editStatus.value = false;
getProjectInfo();
});
})
.catch((err) => {
console.log(err);
});
};
// excel
let stockList = ref([]);
let baseUrl = ref(request.userCustom);
/**
* 上传股权结构文件
*/
const getFileInfo = (info) => {
console.log(info);
if (info.file.response) {
if (info.file.response.code == 200) {
getStockInfoList();
message.success("导入成功");
}
}
};
/**
* 上传增资扩股文件
*/
const getMoreInfo = (info) => {
console.log(info);
if (info.file.response) {
if (info.file.response.code == 200) {
getStockMoreList();
message.success("导入成功");
}
}
};
</script>
<style lang="less" scoped>
/deep/ .ant-upload-list-text {
display: none !important;
}
</style>

@ -1,157 +0,0 @@
<template>
<!--我的职位-->
<div class="p-manage-myJob">
<div class="m-select g_flex_row_between">
<!-- <div class="g_flex_row_start">
<div class="g_w_320 g-search-btn g_mr_16">
<a-input-search v-model:value="tableData.keyword" placeholder="请输入姓名" @search="searchList" @change="handleChangeSearch" allowClear />
</div>
</div> -->
<div>
<!-- <a-button type="primary" @click="openAdd" :icon="h(PlusOutlined)">新增用户</a-button> -->
<!-- <a-button type="" class="g_border_d g_ml_16" @click="handleToForm('add', { id: 0 })" :icon="h(DownloadOutlined)">导出模版</a-button> -->
<!--
<a-dropdown :trigger="['click']">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="goShareList"></a-menu-item>
<a-menu-item key="2" @click="handleToForm('add',{id:0})"></a-menu-item>
</a-menu>
</template>
<a-button>
新增职位
<DownOutlined style="zoom:.8" />
</a-button>
</a-dropdown> -->
</div>
</div>
<div class="m-table g_mt_20 antd-table">
<a-table sticky :columns="columns" :scroll="{x:1000}" :data-source="tableData.records" size="middle" :pagination="false" :loading="tableData.loading" class="g_clear_scroll" style="max-width: calc(100% - 0px)">
<template #bodyCell="{ column, record }">
</template>
</a-table>
<div class="g_pb_16 g_pt_16 g_pageBottom" v-if="tableData.records.length > 0">
<a-pagination v-model:current="tableData.page" v-model:page-size="tableData.size" :total="tableData.total" :pageSize="tableData.size" :show-total="(total) => `${total}`" @change="handleModalPage" @showSizeChange="handleModalSize" :show-quick-jumper="tableData.total < tableData.size ? false : true" :showSizeChanger="tableData.total < tableData.size ? false : true" :hideOnSinglePage="false" />
</div>
</div>
</div>
</template>
<script setup>
import request from "../../utils/request"; //
import { ref, onMounted, getCurrentInstance, h, watch } from "vue";
import { PlusOutlined, EllipsisOutlined, UploadOutlined, DownOutlined } from "@ant-design/icons-vue";
import { Modal, message } from "ant-design-vue";
import { useRouter, useRoute } from "vue-router";
import {getLoginLogApi} from "../../api/login";
import { DownloadOutlined } from "@ant-design/icons-vue";
import idCardPanel from "../components/upload/image.vue";
/* #################### 初始化事件 #################### */
const router = useRouter(); //
const route = useRoute();
const commonJS = getCurrentInstance().appContext.app.config.globalProperties.G;
onMounted(() => {
getTable();
});
/* #################### 表格事件 #################### */
const tableData = ref({
keyword: "",
page: 1,
limit: 20,
total: 0,
count: 0,
loading: false,
records: [],
});
const getTable = () => {
console.log(tableData.value);
tableData.value.loading = true;
getLoginLogApi({ limit: tableData.value.limit, page: tableData.value.page}).then((res) => {
console.log(res);
tableData.value = { ...res.data, page: res.data.current, limit: res.data.size };
tableData.value.records.forEach((item, index) => {
item.rank = index + 1;
});
});
};
const columns = ref([
{
title: "序号",
key: "rank",
dataIndex: "rank",
width: "50px",
ellipsis: true,
},
{
title: "姓名",
key: "username",
width:"120px",
dataIndex: "username",
},
{
title: "电话",
key: "name",
width:"180px",
dataIndex: "name",
},
{
title: "登录时间",
key: "updateTime",
dataIndex: "updateTime",
ellipsis: true,
},
]);
/* #################### 分页器事件 #################### */
const handleModalPage = ($page, $size) => {
//
console.log($page);
console.log($size);
tableData.value.page = $page;
getTable();
};
const handleModalSize = ($page, $size) => {
// size
tableData.value.page = 1;
tableData.value.size = $size;
getTable();
};
</script>
<style lang="less">
.ant-table-cell:empty::before{
content: "-";
}
.p-manage-myJob {
position: relative;
min-height: calc(100vh - 213px);
width: 100%;
height: 100px;
.btn-active {
width: 40px;
height: 24px;
margin-left: 6.5px;
font-size: 12px;
color: #f6343e;
background-color: #fff3f3;
padding: 1px 3px;
zoom: 0.6;
margin-top: 8px;
text-align: center;
}
}
.ant-spin-blur .ant-empty {
opacity: 0;
}
</style>

@ -105,8 +105,8 @@ const loginType = ref(1);
//
const loginInfo = ref({
username: "bocai",
password: "123456",
username: "admin",
password: "1111111",
code: "",
});
const loginInfoForm = ref();
@ -119,25 +119,6 @@ const watchValidate = (e1) => {
const submitInfo = (e) => {
let obj = e;
router.push("/merchantManagement/homePage");
return
// if (loginType.value == 2) {
// obj.loginType = 1;
// } else {
@ -156,11 +137,11 @@ const submitInfo = (e) => {
infoApi({}).then((res) => {
console.log("infoApi", res);
// localStorage.setItem("DAOTIAN_userinfo", JSON.stringify(res.data));
localStorage.setItem("DAOTIAN_userinfo_name", res.data.name || res.data.name);
localStorage.setItem("DAOTIAN_userinfo_avatar", res.data.avatar);
// localStorage.setItem("DAOTIAN_userinfo_name", res.data.name || res.data.name);
// localStorage.setItem("DAOTIAN_userinfo_avatar", res.data.avatar);
// localStorage.setItem("DAOTIAN_userinfo_roleid", res.data.user.agencyRoleId);
// localStorage.setItem("DAOTIAN_userinfo_agencyid", res.data.user.agencyId);
router.push("/merchantManagement/homePage");
router.push("/merchantManagement/message");
message.success("登录成功");
});
});

@ -15,53 +15,66 @@
/>
</div>
</template>
<script>
import '@wangeditor/editor/dist/css/style.css' // css
import { onBeforeUnmount, ref, shallowRef, onMounted } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
<script setup>
import '@wangeditor/editor/dist/css/style.css'
import { onBeforeUnmount, ref, shallowRef, onMounted, watch } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
export default {
components: { Editor, Toolbar },
setup() {
// shallowRef
const editorRef = shallowRef()
const props = defineProps({
modelValue: {
type: String,
default: '',
},
});
// HTML
const valueHtml = ref('<p>hello</p>')
const emit = defineEmits(['update:modelValue', 'image-upload']);
// ajax
onMounted(() => {
setTimeout(() => {
valueHtml.value = '<p>模拟 Ajax 异步设置内容</p>'
}, 1500)
})
const editorRef = shallowRef();
const valueHtml = ref(props.modelValue);
const toolbarConfig = {}
const editorConfig = { placeholder: '请输入内容...' }
watch(() => props.modelValue, (newValue) => {
if (newValue !== valueHtml.value) {
valueHtml.value = newValue;
}
});
//
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor == null) return
editor.destroy()
})
watch(valueHtml, (newValue) => {
emit('update:modelValue', newValue);
});
const handleCreated = (editor) => {
editorRef.value = editor // editor
}
const toolbarConfig = {};
const editorConfig = {
placeholder: '请输入内容...',
MENU_CONF: {}
};
return {
editorRef,
valueHtml,
mode: 'default', // 'simple'
toolbarConfig,
editorConfig,
handleCreated,
}
},
editorConfig.MENU_CONF['uploadImage'] = {
async customUpload(file, insertFn) {
const url = await emit('image-upload', file);
if (url) {
insertFn(url);
}
}
};
onBeforeUnmount(() => {
const editor = editorRef.value;
if (editor == null) return;
editor.destroy();
});
const handleCreated = (editor) => {
editorRef.value = editor;
};
onMounted(() => {
setTimeout(() => {
valueHtml.value = props.modelValue;
}, 100);
});
</script>
<style scoped>
.wysiwyg-editor {
border: 1px solid #ccc;

@ -0,0 +1,262 @@
<template>
<div class="content-management">
<a-tabs v-model:activeKey="activeTab" @change="tabChange">
<a-tab-pane key="recommendations" tab="今日推荐"></a-tab-pane>
<a-tab-pane key="stores" tab="门店"></a-tab-pane>
<a-tab-pane key="events" tab="赛事分析"></a-tab-pane>
<template #rightExtra>
<a-button type="primary" @click="showAddModal"></a-button>
</template>
</a-tabs>
<a-table :columns="columns" :data-source="filteredData" :rowKey="record => record.id">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'content'">
<div v-if="record.classify === 1">
<a-image
:src="record.img"
:width="50"
:height="50"
style="margin-right: 5px;"
/>
</div>
<span v-else v-html="record.content"></span>
</template>
<template v-if="column.key === 'status'">
<a-tag :color="record.status === 1 ? 'green' : 'orange'">
{{ record.status === 1 ? '已发布' : '未发布' }}
</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a-button type="link" @click="editItem(record)"></a-button>
<a-button type="link" @click="deleteItem(record)"></a-button>
</a-space>
</template>
</template>
</a-table>
<a-modal
v-model:visible="modalVisible"
:title="modalMode === 'add' ? '新增内容' : '编辑内容'"
@ok="handleModalOk"
@cancel="handleModalCancel"
width="800px"
>
<a-form :model="formState" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
<a-form-item label="类型">
<a-select v-model:value="formState.classify" :disabled="modalMode === 'edit'">
<a-select-option :value="1">今日推荐</a-select-option>
<a-select-option :value="0">门店</a-select-option>
<a-select-option :value="2">赛事分析</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="标题">
<a-input v-model:value="formState.title" placeholder="输入标题"/>
</a-form-item>
<a-form-item label="主图">
<a-upload
v-model:fileList="formState.images"
list-type="picture-card"
:max-count="1"
@preview="handlePreview"
@change="handleImageChange"
:customRequest="customRequest"
>
<div v-if="formState.images.length < 1">
<plus-outlined />
<div style="margin-top: 8px">上传图片</div>
</div>
</a-upload>
</a-form-item>
<a-form-item label="内容" v-if="formState.classify !== 1">
<wysiwyg-editor v-model="formState.content" @image-upload="handleEditorImageUpload" />
</a-form-item>
<a-form-item label="状态">
<a-switch v-model:checked="formState.status" :checked-value="1" :unchecked-value="0" />
</a-form-item>
</a-form>
</a-modal>
<a-modal v-model:visible="previewVisible" :title="previewTitle" :footer="null">
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal>
</div>
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue';
import { message } from 'ant-design-vue';
import { PlusOutlined } from '@ant-design/icons-vue';
import WysiwygEditor from './WysiwygEditor.vue';
import { saveContentApi, updateContentApi, getContentListApi, deleteContentApi, uploadImageApi } from "../../api/contentConfig";
const activeTab = ref('recommendations');
const modalVisible = ref(false);
const modalMode = ref('add');
const previewVisible = ref(false);
const previewImage = ref('');
const previewTitle = ref('');
const columns = [
{ title: '类型', dataIndex: 'classify', key: 'classify' },
{ title: '标题', dataIndex: 'title', key: 'title' },
{ title: '内容', dataIndex: 'content', key: 'content' },
{ title: '状态', dataIndex: 'status', key: 'status' },
{ title: '操作', key: 'action' },
];
const data = reactive([]);
const classify = ref(0);
const formState = reactive({
id: null,
classify: 1,
title: '',
content: '',
img: '',
images: [],
status: 0,
});
const filteredData = computed(() => {
const tabToClassify = {
'recommendations': 1,
'stores': 0,
'events': 2
};
return data.filter(item => item.classify === tabToClassify[activeTab.value]);
});
const showAddModal = () => {
modalMode.value = 'add';
const tabToClassify = {
'recommendations': 1,
'stores': 0,
'events': 2
};
Object.assign(formState, { id: null, classify: tabToClassify[activeTab.value], title: '', content: '', img: '', images: [], status: 0 });
modalVisible.value = true;
};
const editItem = (record) => {
modalMode.value = 'edit';
Object.assign(formState, {
...record,
images: record.img ? [{
uid: -1,
name: 'image.jpg',
status: 'done',
url: record.img,
}] : []
});
modalVisible.value = true;
};
const deleteItem = async (record) => {
try {
await deleteContentApi(record.id);
message.success('删除成功');
fetchData();
} catch (error) {
message.error('删除失败');
}
};
const handleModalOk = async () => {
try {
const data = {
classify: formState.classify,
title: formState.title,
content: formState.classify === 1 ? '' : formState.content,
img: formState.img,
status: formState.status,
};
if (modalMode.value === 'add') {
await saveContentApi(data);
} else {
await updateContentApi({ ...data, id: formState.id });
}
message.success(modalMode.value === 'add' ? '添加成功' : '编辑成功');
modalVisible.value = false;
fetchData();
} catch (error) {
message.error(modalMode.value === 'add' ? '添加失败' : '编辑失败');
}
};
const handleModalCancel = () => {
modalVisible.value = false;
};
const tabChange = (activeKey) => {
classify.value = activeKey === 'recommendations' ? 1 : activeKey === 'stores' ? 0 : 2;
fetchData();
};
const handlePreview = async (file) => {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj);
}
previewImage.value = file.url || file.preview;
previewVisible.value = true;
previewTitle.value = file.name || file.url.substring(file.url.lastIndexOf('/') + 1);
};
const customRequest = async ({ file, onSuccess, onError }) => {
try {
const response = await uploadImageApi(file);
formState.img = response.data;
onSuccess(response, file);
} catch (error) {
onError(error);
}
};
const handleImageChange = ({ fileList }) => {
formState.images = fileList;
};
const handleEditorImageUpload = async (file) => {
try {
const response = await uploadImageApi(file);
return response.data; // Return the image URL
} catch (error) {
message.error('图片上传失败');
return '';
}
};
const getBase64 = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
};
const fetchData = async () => {
try {
const response = await getContentListApi(1, 10, classify.value);
data.splice(0, data.length, ...response.data.records);
} catch (error) {
message.error('获取数据失败');
}
};
onMounted(() => {
fetchData();
});
</script>
<style scoped>
.content-management {
padding: 24px;
}
.table-actions {
margin-bottom: 16px;
text-align: right;
}
</style>

@ -1,31 +1,23 @@
<template>
<div class="content-management">
<a-tabs v-model:activeKey="activeTab">
<a-tab-pane key="stores" tab="门店"></a-tab-pane>
<a-tab-pane key="recommendations" tab="今日推荐"></a-tab-pane>
<a-tab-pane key="events" tab="赛事分析"></a-tab-pane>
<a-tab-pane key="carousel" tab="轮播"></a-tab-pane>
</a-tabs>
<div class="carousel-management">
<div class="table-actions">
<a-button type="primary" @click="showAddModal"></a-button>
</div>
<a-table :columns="columns" :data-source="filteredData" :rowKey="record => record.id">
<a-table :columns="columns" :data-source="data" :rowKey="record => record.id">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'content'">
<div v-if="['recommendations', 'carousel'].includes(record.type) && Array.isArray(record.content)">
<a-image
v-for="(image, index) in record.content.slice(0, 3)"
:key="index"
:src="image"
:width="50"
:height="50"
style="margin-right: 5px;"
/>
<span v-if="record.content.length > 3">+{{ record.content.length - 3 }} more</span>
</div>
<span v-else v-html="record.content"></span>
<template v-if="column.key === 'img'">
<a-image
:src="record.img"
:width="50"
:height="50"
style="margin-right: 5px;"
/>
</template>
<template v-if="column.key === 'status'">
<a-tag :color="record.status === 1 ? 'green' : 'red'">
{{ record.status === 1 ? '启用' : '不启用' }}
</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
@ -38,39 +30,32 @@
<a-modal
v-model:visible="modalVisible"
:title="modalMode === 'add' ? '新增内容' : '编辑内容'"
:title="modalMode === 'add' ? '新增轮播图' : '编辑轮播图'"
@ok="handleModalOk"
@cancel="handleModalCancel"
width="800px"
>
<a-form :model="formState" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
<a-form-item label="类型">
<a-select v-model:value="formState.type" :disabled="modalMode === 'edit'">
<a-select-option value="stores">门店</a-select-option>
<a-select-option value="recommendations">今日推荐</a-select-option>
<a-select-option value="events">赛事分析</a-select-option>
<a-select-option value="carousel">轮播</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="标题">
<a-input v-model:value="formState.title" placeholder="输入标题"/>
<a-form-item label="标题" name="title" :rules="[{ required: true, message: '请输入标题' }]">
<a-input v-model:value="formState.title" />
</a-form-item>
<a-form-item label="图片" v-if="['recommendations', 'carousel'].includes(formState.type)">
<a-form-item label="图片" name="img" :rules="[{ required: true, message: '请上传图片' }]">
<a-upload
v-model:fileList="formState.images"
list-type="picture-card"
:max-count="formState.type === 'carousel' ? 1 : 9"
:max-count="1"
@preview="handlePreview"
@change="handleImageChange"
:customRequest="customRequest"
>
<div v-if="formState.images.length < (formState.type === 'carousel' ? 1 : 9)">
<div v-if="formState.images.length < 1">
<plus-outlined />
<div style="margin-top: 8px">上传图片</div>
</div>
</a-upload>
</a-form-item>
<a-form-item label="内容" v-if="!['recommendations', 'carousel'].includes(formState.type)">
<wysiwyg-editor v-model="formState.content" />
<a-form-item label="状态" name="status">
<a-switch v-model:checked="formState.status" :checked-value="1" :unchecked-value="0" />
</a-form-item>
</a-form>
</a-modal>
@ -82,12 +67,11 @@
</template>
<script setup>
import { ref, reactive, computed } from 'vue';
import { ref, reactive, onMounted } from 'vue';
import { message } from 'ant-design-vue';
import { PlusOutlined } from '@ant-design/icons-vue';
import WysiwygEditor from './WysiwygEditor.vue';
import { getCarouselListApi, saveCarouselApi, deleteCarouselApi, updateCarouselApi, uploadImageApi } from "../../api/carouselConfig";
const activeTab = ref('stores');
const modalVisible = ref(false);
const modalMode = ref('add');
const previewVisible = ref(false);
@ -95,88 +79,80 @@ const previewImage = ref('');
const previewTitle = ref('');
const columns = [
{ title: '类型', dataIndex: 'type', key: 'type' },
{ title: '标题', dataIndex: 'title', key: 'title' },
{ title: '内容', dataIndex: 'content', key: 'content' },
{ title: '图片', dataIndex: 'img', key: 'img' },
{ title: '状态', dataIndex: 'status', key: 'status' },
{ title: '操作', key: 'action' },
];
const data = reactive([
{ id: 1, type: 'stores', title: '门店1', content: '<p>门店1的内容...</p>' },
{ id: 2, type: 'recommendations', title: '推荐1', content: ['https://matripe.oss-cn-beijing.aliyuncs.com/default.png', 'https://matripe.oss-cn-beijing.aliyuncs.com/default.png'] },
{ id: 3, type: 'events', title: '赛事1', content: '<p>赛事1的分析...</p>' },
{ id: 4, type: 'carousel', title: '轮播1', content: ['https://matripe.oss-cn-beijing.aliyuncs.com/default.png'] },
]);
const data = reactive([]);
const formState = reactive({
id: null,
type: 'stores',
title: '',
content: '',
images: [],
});
const filteredData = computed(() => {
return data.filter(item => item.type === activeTab.value);
img: '',
status: 1,
});
const showAddModal = () => {
modalMode.value = 'add';
Object.assign(formState, { id: null, type: activeTab.value, title: '', content: '', images: [] });
Object.assign(formState, { id: null, title: '', images: [], img: '', status: 1 });
modalVisible.value = true;
};
const editItem = (record) => {
modalMode.value = 'edit';
if (['recommendations', 'carousel'].includes(record.type)) {
Object.assign(formState, {
...record,
images: record.content.map((url, index) => ({
uid: -index,
name: `image${index + 1}.jpg`,
status: 'done',
url: url,
}))
});
} else {
Object.assign(formState, { ...record, images: [] });
}
Object.assign(formState, {
id: record.id,
title: record.title,
images: [{
uid: -1,
name: 'image.jpg',
status: 'done',
url: record.img,
}],
img: record.img,
status: record.status,
});
modalVisible.value = true;
};
const deleteItem = (record) => {
const index = data.findIndex(item => item.id === record.id);
if (index !== -1) {
data.splice(index, 1);
const deleteItem = async (record) => {
try {
await deleteCarouselApi(record.id);
message.success('删除成功');
fetchData();
} catch (error) {
message.error('删除失败');
}
};
const handleModalOk = () => {
if (modalMode.value === 'add') {
data.push({
id: Date.now(),
type: formState.type,
const handleModalOk = async () => {
console.log(formState);
try {
const data = {
title: formState.title,
content: ['recommendations', 'carousel'].includes(formState.type)
? formState.images.map(img => img.url || img.response.url)
: formState.content,
});
message.success('添加成功');
} else {
const index = data.findIndex(item => item.id === formState.id);
if (index !== -1) {
Object.assign(data[index], {
type: formState.type,
title: formState.title,
content: ['recommendations', 'carousel'].includes(formState.type)
? formState.images.map(img => img.url || img.response.url)
: formState.content,
});
message.success('编辑成功');
img: formState.img,
status: formState.status
};
if (modalMode.value === 'add') {
console.log(data);
await saveCarouselApi(data);
} else {
await updateCarouselApi({ ...data, id: formState.id });
}
message.success(modalMode.value === 'add' ? '添加成功' : '编辑成功');
modalVisible.value = false;
fetchData();
} catch (error) {
message.error(modalMode.value === 'add' ? '添加失败' : '编辑失败');
}
modalVisible.value = false;
};
const handleModalCancel = () => {
@ -192,8 +168,22 @@ const handlePreview = async (file) => {
previewTitle.value = file.name || file.url.substring(file.url.lastIndexOf('/') + 1);
};
const customRequest = async ({ file, onSuccess, onError }) => {
try {
const response = await uploadImageApi(file);
formState.img = response.data.url;
onSuccess(response, file);
} catch (error) {
onError(error);
}
};
const handleImageChange = ({ fileList }) => {
formState.images = fileList;
if (fileList.length > 0) {
const lastFile = fileList[fileList.length - 1];
formState.img = lastFile.response ? lastFile.response.data : lastFile.url;
}
};
const getBase64 = (file) => {
@ -204,14 +194,28 @@ const getBase64 = (file) => {
reader.onerror = error => reject(error);
});
};
const fetchData = async () => {
try {
const response = await getCarouselListApi(1);
data.splice(0, data.length, ...response.data.records);
} catch (error) {
message.error('获取数据失败');
}
};
onMounted(() => {
fetchData();
});
</script>
<style scoped>
.content-management {
.carousel-management {
padding: 24px;
}
.table-actions {
margin-bottom: 16px;
text-align: right;
}
</style>
</style>

Loading…
Cancel
Save