- 框架初始化
 - 安装插件
 - 修复PHP8.4报错
This commit is contained in:
2025-04-19 17:21:20 +08:00
commit c6a4e1f5f6
5306 changed files with 967782 additions and 0 deletions

View File

@@ -0,0 +1,145 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'moment'], function ($, undefined, Backend, Table, Form, Moment) {
var Controller = {
add: () => {
Controller.form();
},
edit: () => {
Controller.form();
},
form: () => {
const { reactive, onMounted } = Vue
const addEdit = {
setup() {
const state = reactive({
type: new URLSearchParams(location.search).get('type'),
id: new URLSearchParams(location.search).get('id'),
title: new URLSearchParams(location.search).get('title'),
})
const form = reactive({
model: {
type: 0,
name: '',
price_type: 1,
third_party_appid: '',
price: '',
price2: '',
cover_img_url: '',
},
rules: {
name: [{ validator: checkTitle, trigger: 'change' }],
cover_img_url: [{ required: true, message: '请选择商品封面', trigger: 'change' }],
},
});
const goods = reactive({
id: '', // 商品id
image: '', // 商品图片
title: '', // 商品名称
});
function checkTitle(rule, value, callback) {
if (!value) {
return callback(new Error('请输入商品名称'));
}
const length =
value.match(/[^ -~]/g) == null ? value.length : value.length + value.match(/[^ -~]/g).length;
if (length < 6 || length > 28) {
callback(new Error('直播标题必须为3-14个字一个字等于两个英文字符或特殊字符'));
} else {
callback();
}
}
//选择商品
function selectGoods() {
let id = '';
Fast.api.open(`shopro/goods/goods/select`, "选择商品", {
callback(data) {
console.log(data, 'data');
goods.image = data.image;
goods.title = data.title;
goods.id = data.id;
form.model.cover_img_url = data.image;
form.model.name = data.title;
form.model.url = 'pages/goods/index?id=' + goods.id;
if (data.price.length === 2) {
form.model.price_type = 2;
form.model.price = data.price[0];
form.model.price2 = data.price[1];
} else {
if (Number(data.original_price)) {
form.model.price_type = 3;
form.model.price = data.original_price;
form.model.price2 = data.price[0];
} else {
form.model.price_type = 1;
form.model.price = data.price[0];
}
}
form.model.goods_id = data.id;
}
})
}
// 获取商品信息
function getGoodsList(id) {
Fast.api.ajax({
url: `shopro/goods/goods/select`,
type: 'GET',
data: {
type: 'select',
search: JSON.stringify({ id }),
},
}, function (ret, res) {
goods.image = res.data[0].image;
goods.title = res.data[0].title;
return false
}, function (ret, res) { })
}
//获取详情
function getDetail() {
Fast.api.ajax({
url: `shopro/app/mplive/goods/detail/id/${state.id}`,
type: 'GET',
}, function (ret, res) {
form.model = res.data;
getGoodsList(form.model.goods_id);
return false
}, function (ret, res) { })
}
function onConfirm() {
Fast.api.ajax({
url: state.type == 'add' ? 'shopro/app/mplive/goods/add' : `shopro/app/mplive/goods/edit/id/${state.id}`,
type: 'POST',
data: form.model,
}, function (ret, res) {
Fast.api.close()
}, function (ret, res) { })
}
onMounted(() => {
state.type == 'edit' && getDetail()
})
return {
state,
goods,
form,
onConfirm,
getDetail,
checkTitle,
selectGoods,
getGoodsList
}
}
}
createApp('addEdit', addEdit);
},
};
return Controller;
});

View File

@@ -0,0 +1,260 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'moment'], function ($, undefined, Backend, Table, Form, Moment) {
var Controller = {
index: () => {
const { reactive, onMounted, ref, watch } = Vue
const index = {
setup() {
const state = reactive({
status: 0,
data: [],
filter: {
drawer: false,
data: {
name: '',
},
tools: {
name: {
type: 'tinput',
field: 'name',
value: '',
label: '商品名称',
placeholder: '请输入商品名称',
},
},
condition: {}
}
})
const dispatchType = ref('live');
// 直播间表格
const live = reactive({
data: [],
order: '',
sort: '',
selected: [],
});
//商品库表格
const goods = reactive({
data: [],
order: '',
sort: '',
});
// 获取直播间数据
function getLiveData() {
Fast.api.ajax({
url: 'shopro/app/mplive/room',
type: 'GET',
data: {
sort: live.sort,
order: live.order
},
}, function (ret, res) {
live.data = res.data;
return false
}, function (ret, res) { })
}
function getData() {
let tempSearch = JSON.parse(JSON.stringify(state.filter.data));
let search = composeFilter(tempSearch, {
name: 'like',
});
Fast.api.ajax({
url: 'shopro/app/mplive/goods',
type: 'GET',
data: {
page: pagination.page,
list_rows: pagination.list_rows,
...search,
},
}, function (ret, res) {
goods.data = res.data.data
pagination.total = res.data.total
return false
}, function (ret, res) { })
}
function formatPrice(price, type) {
if (type === 1) {
return '';
} else if (type === 2) {
return '~' + price + '元';
} else {
return price + '元';
}
}
function onOpenFilter() {
state.filter.drawer = true
}
function onChangeFilter() {
pagination.page = 1
getData()
state.filter.drawer && (state.filter.drawer = false)
}
const pagination = reactive({
page: 1,
list_rows: 10,
total: 0,
})
function addRow() {
Fast.api.open(`shopro/app/mplive/room/add?type=add`, "添加直播间", {
callback() {
getLiveData()
}
})
}
function editRow(id) {
Fast.api.open(`shopro/app/mplive/room/edit?type=edit&id=${id}`, "编辑直播间", {
callback() {
getLiveData()
}
})
}
function deleteApi(id) {
Fast.api.ajax({
url: `shopro/app/mplive/room/delete/id/${id}`,
type: 'DELETE',
}, function (ret, res) {
getLiveData()
}, function (ret, res) { })
}
//表格排序
function onChangeSort({ prop, order }) {
live.order = order == 'ascending' ? 'asc' : 'desc';
live.sort = prop;
getLiveData();
}
//推流地址
async function pushUrl(id) {
Fast.api.open(`shopro/app/mplive/room/pushUrl?id=${id}`, "推流地址", {
callback() {
getLiveData()
}
})
}
//分享二维码
async function shareQrcode(id) {
Fast.api.open(`shopro/app/mplive/room/qrcode?id=${id}`, "分享二维码", {
callback() {
getLiveData()
}
})
}
//同步直播间
function sync() {
Fast.api.ajax({
url: `shopro/app/mplive/room/sync`,
type: 'GET',
}, function (ret, res) {
live.data = res.data;
}, function (ret, res) { })
}
//直播回放
function playBack(id) {
Fast.api.open(`shopro/app/mplive/room/playback?id=${id}`, "直播回放列表", {
callback() {
getLiveData()
}
})
}
//添加商品
function addGoods() {
Fast.api.open(`shopro/app/mplive/goods/add?type=add`, "添加商品", {
callback() {
getData()
}
})
}
//编辑商品
function editGoods(id) {
Fast.api.open(`shopro/app/mplive/goods/edit?type=edit&id=${id}`, "编辑商品", {
callback() {
getData()
}
})
}
// 删除商品
function deleteGoods(id) {
Fast.api.ajax({
url: `shopro/app/mplive/goods/delete/id/${id}`,
type: 'DELETE',
}, function (ret, res) {
getData()
}, function (ret, res) { })
}
// 获取状态
function getStatus(id) {
Fast.api.ajax({
url: `shopro/app/mplive/goods/status/id/${id}`,
type: 'GET',
}, function (ret, res) {
getData()
}, function (ret, res) { })
}
//审核
function check(id, act) {
Fast.api.ajax({
url: `shopro/app/mplive/goods/audit/id/${id}`,
type: 'POST',
data: {
act
},
}, function (ret, res) {
getData()
}, function (ret, res) { })
}
watch(() => dispatchType.value, () => {
if (dispatchType.value === 'live') {
getLiveData()
} else {
getData()
}
})
onMounted(() => {
getLiveData()
})
return {
state,
live,
goods,
dispatchType,
getData,
onOpenFilter,
onChangeFilter,
pagination,
formatPrice,
getLiveData,
addRow,
editRow,
deleteApi,
Moment,
sync,
playBack,
shareQrcode,
pushUrl,
addGoods,
editGoods,
deleteGoods,
check,
getStatus,
onChangeSort
}
}
}
createApp('index', index);
},
};
return Controller;
});

View File

@@ -0,0 +1,329 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'moment'], function ($, undefined, Backend, Table, Form, Moment) {
var Controller = {
add: () => {
Controller.form();
},
edit: () => {
Controller.form();
},
form: () => {
const { reactive, onMounted, ref } = Vue
const addEdit = {
setup() {
const state = reactive({
type: new URLSearchParams(location.search).get('type'),
id: new URLSearchParams(location.search).get('id'),
title: new URLSearchParams(location.search).get('title'),
})
const form = reactive({
model: {
way: 'column',
type: 0,
name: '',
date_time: '',
anchor_name: '',
anchor_wechat: '',
sub_anchor_wechat: '',
is_feeds_public: 1,
close_kf: 0,
close_replay: 0,
close_comment: 0,
close_goods: 0,
close_like: 0,
feeds_img: '',
share_img: '',
cover_img: '',
},
rules: {
type: [{ required: true, message: '请选择直播类型', trigger: 'change' }],
way: [{ required: true, message: '请选择播放方式', trigger: 'change' }],
feeds_img: [{ required: true, message: '请选择封面图', trigger: 'change' }],
share_img: [{ required: true, message: '请选择分享图', trigger: 'change' }],
cover_img: [{ required: true, message: '请选择背景图', trigger: 'change' }],
date_time: [{ required: true, message: '请选择开播时间', trigger: 'change' }],
name: [{ required: true, message: '请输入直播间标题', trigger: 'blur' }, { validator: checkTitle, trigger: 'change' }],
anchor_name: [{ required: true, message: '请输入主播昵称', trigger: 'blur' }, { validator: checkNickname, trigger: 'change' }],
anchor_wechat: [{ required: true, message: '请输入主播微信账号', trigger: 'blur' }],
},
});
//获取默认开始时间为当前时间后40分钟
const defaultTime = ref([
new Date(new Date().getTime() + 40 * 60 * 1000),
new Date(2000, 2, 1, 23, 59, 59),
]);
// 禁止时间
function disabledDate(time) {
return time.getTime() < Date.now() - 86400000;
}
// 获取详情
function getDetail() {
Fast.api.ajax({
url: `shopro/app/mplive/room/detail/id/${state.id}`,
type: 'GET',
}, function (ret, res) {
form.model = res.data;
form.model.date_time = [
Moment(res.data.start_time * 1000).format('YYYY-MM-DD HH:mm:ss'),
Moment(res.data.end_time * 1000).format('YYYY-MM-DD HH:mm:ss'),
];
return false
}, function (ret, res) { })
}
function onConfirm() {
let submitForm = {
...form.model,
start_time: Number(new Date(form.model.date_time[0]).getTime() / 1000),
end_time: Number(new Date(form.model.date_time[1]).getTime() / 1000),
}
delete submitForm.date_time
Fast.api.ajax({
url: state.type == 'add' ? 'shopro/app/mplive/room/add' : `shopro/app/mplive/room/edit/id/${state.id}`,
type: 'POST',
data: submitForm,
}, function (ret, res) {
Fast.api.close()
}, function (ret, res) { })
}
function checkTitle(rule, value, callback) {
if (!value) {
return callback(new Error('请输入直播间标题'));
}
const length =
value.match(/[^ -~]/g) == null ? value.length : value.length + value.match(/[^ -~]/g).length;
if (length < 6 || length > 34) {
callback(new Error('直播标题必须为3-17个字一个字等于两个英文字符或特殊字符'));
} else {
callback();
}
}
function checkNickname(rule, value, callback) {
if (!value) {
return callback(new Error('请输入主播昵称'));
}
const length =
value.match(/[^ -~]/g) == null ? value.length : value.length + value.match(/[^ -~]/g).length;
if (length < 4 || length > 30) {
callback(new Error('直播标题必须为2-15个字一个字等于两个英文字符或特殊字符'));
} else {
callback();
}
}
onMounted(() => {
state.type == 'edit' && getDetail()
})
return {
state,
form,
disabledDate,
onConfirm,
getDetail,
checkTitle,
checkNickname,
defaultTime
}
}
}
createApp('addEdit', addEdit);
},
select: () => {
const { reactive, onMounted } = Vue
const select = {
setup() {
const state = reactive({
data: [],
selected: [],
});
function getData() {
Fast.api.ajax({
url: 'shopro/app/mplive/room/select',
type: 'GET',
}, function (ret, res) {
state.data = res.data;
return false
}, function (ret, res) { })
}
function isSelectable(row) {
return row.status === 101 || row.status === 102 || row.status === 103
}
function onSelectionChange(val) {
state.selected = val
}
function onConfirm() {
Fast.api.close(state.selected)
}
onMounted(() => {
getData()
})
return {
Moment,
state,
isSelectable,
onSelectionChange,
onConfirm,
}
}
}
createApp('select', select);
},
pushurl: () => {
const { reactive, onMounted } = Vue
const pushUrl = {
setup() {
const state = reactive({
id: new URLSearchParams(location.search).get('id'),
pushUrl: '', // 推流地址
serverAddress: '', // 服务器地址
key: '', // 串流密钥
})
function getDetail() {
Fast.api.ajax({
url: `shopro/app/mplive/room/pushUrl/id/${state.id}`,
type: 'GET',
}, function (ret, res) {
state.pushUrl = res.data.pushAddr;
state.serverAddress = state.pushUrl.split('/live/')[0] + '/live/';
state.key = state.pushUrl.split('/live/')[1];
return false
}, function (ret, res) { })
}
function onJump() {
window.open('https://docs.qq.com/doc/DV0hoWHZRdm9oT2pp');
}
onMounted(() => {
getDetail()
})
return {
state,
getDetail,
onClipboard,
onJump
}
}
}
createApp('pushUrl', pushUrl);
},
qrcode: () => {
const { reactive, onMounted } = Vue
const qrcode = {
setup() {
const state = reactive({
id: new URLSearchParams(location.search).get('id'),
cdnUrl: '', // 小程序码
path: '', // 页面路径
key: '', // 串流密钥
})
function getDetail() {
Fast.api.ajax({
url: `shopro/app/mplive/room/qrcode/id/${state.id}`,
type: 'GET',
}, function (ret, res) {
state.cdnUrl = res.data.cdnUrl;
state.path = res.data.pagePath;
return false
}, function (ret, res) { })
}
function saveImg() {
window.open(state.cdnUrl);
}
function onJump() {
window.open(
'https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/liveplayer/live-player-plugin.html',
);
}
onMounted(() => {
getDetail()
})
return {
state,
getDetail,
onClipboard,
saveImg,
onJump
}
}
}
createApp('qrcode', qrcode);
},
playback: () => {
const { reactive, onMounted } = Vue
const playback = {
setup() {
const state = reactive({
id: new URLSearchParams(location.search).get('id'),
})
// 表格状态
const table = reactive({
data: [],
order: '',
sort: '',
selected: [],
});
function getData() {
Fast.api.ajax({
url: `shopro/app/mplive/room/playback/id/${state.id}`,
type: 'GET',
// data: {
// page: pagination.page,
// list_rows: pagination.list_rows,
// order: state.order,
// sort: state.sort,
// },
}, function (ret, res) {
table.data = res.data
table.data.forEach((item, index) => {
table.data[index].index = index + 1;
});
return false
}, function (ret, res) { })
}
const pagination = reactive({
page: 1,
list_rows: 10,
total: 0,
})
function play(url) {
window.open(url);
}
onMounted(() => {
getData()
})
return {
state,
getData,
pagination,
table,
play
}
}
}
createApp('playback', playback);
},
};
return Controller;
});