mirror of
https://gitee.com/niucloud-team/niucloud.git
synced 2026-01-25 03:58:11 +00:00
0.5.2
This commit is contained in:
parent
ecc7c620c1
commit
3dd2b3e0a8
@ -55,4 +55,4 @@
|
|||||||
"vite": "4.1.0",
|
"vite": "4.1.0",
|
||||||
"vue-tsc": "1.0.24"
|
"vue-tsc": "1.0.24"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,6 +184,15 @@ export function unlockUser(uid: number) {
|
|||||||
return request.put(`site/user/unlock/${uid}`)
|
return request.put(`site/user/unlock/${uid}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除用户
|
||||||
|
*
|
||||||
|
* @param uid
|
||||||
|
*/
|
||||||
|
export function deleteUser(uid: number) {
|
||||||
|
return request.delete(`site/user/${uid}`)
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************** 操作日志 **************************************************/
|
/***************************************************** 操作日志 **************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -39,6 +39,14 @@ export function deleteUser(uid: number) {
|
|||||||
return request.delete(`user/user/${uid}`, { showSuccessMessage: true })
|
return request.delete(`user/user/${uid}`, { showSuccessMessage: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改用户
|
||||||
|
* @param uid
|
||||||
|
*/
|
||||||
|
export function editUser(params: Record<string, any>) {
|
||||||
|
return request.put(`user/user/${params.uid}`, params, { showSuccessMessage: true })
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有用户列表
|
* 获取所有用户列表
|
||||||
* @param params
|
* @param params
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
<div class="mt-[20px]" v-for="(item, index) in upgradeContent.version_list" :key="index">
|
<div class="mt-[20px]" v-for="(item, index) in upgradeContent.version_list" :key="index">
|
||||||
<div class="font-bold text-lg">{{ item.version_no }}</div>
|
<div class="font-bold text-lg">{{ item.version_no }}</div>
|
||||||
<div class="mt-[5px]" v-if="item.release_time">{{ item.release_time }}</div>
|
<div class="mt-[5px]" v-if="item.release_time">{{ item.release_time }}</div>
|
||||||
<div class="mt-[10px] p-[10px] rounded bg-[#f4f4f5] whitespace-pre" v-if="item.upgrade_log" v-html="item.upgrade_log"></div>
|
<div class="mt-[10px] p-[10px] rounded bg-[#f4f4f5] whitespace-pre-wrap !break-all" v-if="item.upgrade_log" v-html="item.upgrade_log"></div>
|
||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -28,5 +28,6 @@
|
|||||||
"manager": "用户",
|
"manager": "用户",
|
||||||
"managerPlaceholder": "请选择用户",
|
"managerPlaceholder": "请选择用户",
|
||||||
"managerTips": "选择或者新增用户作为管理员",
|
"managerTips": "选择或者新增用户作为管理员",
|
||||||
"newAddManager": "新增用户"
|
"newAddManager": "新增用户",
|
||||||
}
|
"userDeleteTips": "是否要删除该管理员?"
|
||||||
|
}
|
||||||
|
|||||||
@ -19,5 +19,6 @@
|
|||||||
"dataValuePlaceholder":"请输入数据值",
|
"dataValuePlaceholder":"请输入数据值",
|
||||||
"sortPlaceholder":"数值越大越排前",
|
"sortPlaceholder":"数值越大越排前",
|
||||||
"momePlaceholder":"请输入备注",
|
"momePlaceholder":"请输入备注",
|
||||||
"createTime":"创建时间"
|
"createTime":"创建时间",
|
||||||
}
|
"keyFormatTips": "关键字只允许输入字母和下划线"
|
||||||
|
}
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
"title": "插件名称",
|
"title": "插件名称",
|
||||||
"key": "插件标识"
|
"key": "插件标识",
|
||||||
|
"type": "插件类型",
|
||||||
|
"app": "应用",
|
||||||
|
"addon": "插件"
|
||||||
}
|
}
|
||||||
@ -1,48 +1,50 @@
|
|||||||
{
|
{
|
||||||
"orderNo":"订单编号",
|
"orderNo": "订单编号",
|
||||||
"orderStatus":"订单状态",
|
"orderStatus": "订单状态",
|
||||||
"orderNoPlaceholder":"请输入订单编号",
|
"orderNoPlaceholder": "请输入订单编号",
|
||||||
"createTime":"创建时间",
|
"createTime": "创建时间",
|
||||||
"rechargeMoney":"充值金额",
|
"rechargeMoney": "充值金额",
|
||||||
"totalTransfered":"累计提现(元)",
|
"totalTransfered": "累计提现(元)",
|
||||||
"totalCashOuting":"提现中(元)",
|
"totalCashOuting": "提现中(元)",
|
||||||
"transfered":"累计提现",
|
"transfered": "累计提现",
|
||||||
"cashOuting":"提现中",
|
"cashOuting": "提现中",
|
||||||
"orderMoney":"订单金额",
|
"orderMoney": "订单金额",
|
||||||
"member":"买家",
|
"member": "买家",
|
||||||
"orderFromName":"订单来源",
|
"orderFromName": "订单来源",
|
||||||
"payTypeName":"支付方式",
|
"payTypeName": "支付方式",
|
||||||
"startDate":"开始时间",
|
"startDate": "开始时间",
|
||||||
"endDate":"结束时间",
|
"endDate": "结束时间",
|
||||||
"namePlaceholder":"请选择",
|
"namePlaceholder": "请选择",
|
||||||
"applyTime":"申请时间",
|
"applyTime": "申请时间",
|
||||||
"cashOutStatus":"提现状态",
|
"cashOutStatus": "提现状态",
|
||||||
"actualTransferAmount":"实际转账金额",
|
"actualTransferAmount": "实际转账金额",
|
||||||
"cashOutCommission":"提现手续费",
|
"cashOutCommission": "提现手续费",
|
||||||
"applicationForWithdrawalAmount":"申请提现金额",
|
"applicationForWithdrawalAmount": "申请提现金额",
|
||||||
"cashOutMethod":"提现方式",
|
"cashOutMethod": "提现方式",
|
||||||
"cashOutAccountType":"会员账户",
|
"cashOutAccountType": "会员账户",
|
||||||
"memberInfo":"会员信息",
|
"memberInfo": "会员信息",
|
||||||
"toBeReviewed":"待审核",
|
"toBeReviewed": "待审核",
|
||||||
"toBeTransferred":"待转账",
|
"toBeTransferred": "待转账",
|
||||||
"transferred":"已转账",
|
"transferred": "已转账",
|
||||||
"turnDown":"拒绝",
|
"turnDown": "拒绝",
|
||||||
"transfer": "转账",
|
"transfer": "转账",
|
||||||
"detail": "详情",
|
"detail": "详情",
|
||||||
"auditFailure": "审核失败",
|
"auditFailure": "审核失败",
|
||||||
"successfulAudit": "审核成功",
|
"successfulAudit": "审核成功",
|
||||||
"rejectionAudit": "拒绝审核",
|
"rejectionAudit": "拒绝审核",
|
||||||
"reasonsRefusal": "拒绝理由",
|
"reasonsRefusal": "拒绝理由",
|
||||||
"reasonsRefusalPlaceholder": "请输入拒绝理由",
|
"reasonsRefusalPlaceholder": "请输入拒绝理由",
|
||||||
"isTransfer": "是否确认转账",
|
"isTransfer": "是否确认转账",
|
||||||
"nickname":"会员名称",
|
"nickname": "会员名称",
|
||||||
"headimg":"会员头像",
|
"headimg": "会员头像",
|
||||||
"cashOutDetail":"提现详情",
|
"cashOutDetail": "提现详情",
|
||||||
"cashOutMoney": "转账金额",
|
"cashOutMoney": "转账金额",
|
||||||
"auditTime": "审核时间",
|
"auditTime": "审核时间",
|
||||||
"transferTime": "转账时间",
|
"transferTime": "转账时间",
|
||||||
"memberInfoPlaceholder":"请输入会员名称/会员昵称/手机号",
|
"memberInfoPlaceholder": "请输入会员名称/会员昵称/手机号",
|
||||||
"cashOutNumber": "提现单号",
|
"cashOutNumber": "提现单号",
|
||||||
"cashOutNumberPlaceholder": "请输入提现单号"
|
"cashOutNumberPlaceholder": "请输入提现单号",
|
||||||
|
"alipayAccount": "支付宝账号",
|
||||||
|
"bankName": "银行名称",
|
||||||
|
"bankAccount": "银行卡号"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
"calendarSign": "日历签到",
|
"calendarSign": "日历签到",
|
||||||
"periodSign": "周期签到",
|
"periodSign": "周期签到",
|
||||||
"daySignAward": "日签奖励",
|
"daySignAward": "日签奖励",
|
||||||
|
"daySignAwardPlaceholder": "请选择日签奖励",
|
||||||
"continueSignAward": "连签奖励",
|
"continueSignAward": "连签奖励",
|
||||||
"calendarSignTip": "用户根据日期进行打卡,连续签到一定天数可即可获得连签奖励。",
|
"calendarSignTip": "用户根据日期进行打卡,连续签到一定天数可即可获得连签奖励。",
|
||||||
"periodSignTip": "用户在规定的周期内完成签到可以获得奖励;一个周期结束后将进入下一个循环周期。",
|
"periodSignTip": "用户在规定的周期内完成签到可以获得奖励;一个周期结束后将进入下一个循环周期。",
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
"businessHours":"营业时间",
|
"businessHours":"营业时间",
|
||||||
"createTime":"创建时间",
|
"createTime":"创建时间",
|
||||||
"expireTime":"到期时间",
|
"expireTime":"到期时间",
|
||||||
"siteNamePlaceholder":"请输入站点名称",
|
"siteNamePlaceholder":"请输入站点名称/编号",
|
||||||
"createTimePlaceholder":"请输入创建时间",
|
"createTimePlaceholder":"请输入创建时间",
|
||||||
"addSite":"添加站点",
|
"addSite":"添加站点",
|
||||||
"editSite":"编辑站点",
|
"editSite":"编辑站点",
|
||||||
@ -52,5 +52,6 @@
|
|||||||
"siteDomainTipsTwo": "需要将域名配置到您的服务器,同时域名需要解析您的服务器才可生效",
|
"siteDomainTipsTwo": "需要将域名配置到您的服务器,同时域名需要解析您的服务器才可生效",
|
||||||
"siteDomainTipsThree": "站点域名不需要加http或者https,末尾不需要加/",
|
"siteDomainTipsThree": "站点域名不需要加http或者https,末尾不需要加/",
|
||||||
"toSite": "访问站点",
|
"toSite": "访问站点",
|
||||||
"noPermission": "您没有该站点的管理权限"
|
"noPermission": "您没有该站点的管理权限",
|
||||||
|
"closeSiteTips": "是否要停止该站点?"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
"startDate": "开始时间",
|
"startDate": "开始时间",
|
||||||
"loginTime": "最后登录时间",
|
"loginTime": "最后登录时间",
|
||||||
"addUser": "添加用户",
|
"addUser": "添加用户",
|
||||||
|
"updateUser": "编辑用户",
|
||||||
"username": "账号",
|
"username": "账号",
|
||||||
"passwordPlaceholder": "请输入用户密码",
|
"passwordPlaceholder": "请输入用户密码",
|
||||||
"usernamePlaceholder": "请输入用户账号",
|
"usernamePlaceholder": "请输入用户账号",
|
||||||
|
|||||||
@ -29,5 +29,5 @@
|
|||||||
"addCron": "添加任务",
|
"addCron": "添加任务",
|
||||||
"cronTimeTips": "任务周期时间不能为空",
|
"cronTimeTips": "任务周期时间不能为空",
|
||||||
"cronTipsOne": "启动计划任务方式:",
|
"cronTipsOne": "启动计划任务方式:",
|
||||||
"cronTipsTwo": "1、使用命令启动:php think cron:schedule 如果更改了任务周期、状态、删除任务等操作后,需要重新启动下 php think cron:schedule 确保生效"
|
"cronTipsTwo": "1、使用命令启动:php think workerman 如果更改了任务周期、状态、删除任务等操作后,需要重新启动下 php think workerman 确保生效"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,7 +89,7 @@
|
|||||||
<div class="text-page-title mb-[20px]">历史版本</div>
|
<div class="text-page-title mb-[20px]">历史版本</div>
|
||||||
<el-timeline>
|
<el-timeline>
|
||||||
<el-timeline-item :timestamp="item['release_time'] + ' 版本:' + item['version_no']" v-for="(item,index) in frameworkVersionList" type="primary" :hollow="true" placement="top" :key="index">
|
<el-timeline-item :timestamp="item['release_time'] + ' 版本:' + item['version_no']" v-for="(item,index) in frameworkVersionList" type="primary" :hollow="true" placement="top" :key="index">
|
||||||
<div class="mt-[10px] p-[20px] bg-overlay rounded-md timeline-log-wrap whitespace-pre" v-if="item['upgrade_log']">
|
<div class="mt-[10px] p-[20px] bg-overlay rounded-md timeline-log-wrap whitespace-pre-wrap" v-if="item['upgrade_log']">
|
||||||
<div v-html="item['upgrade_log']"></div>
|
<div v-html="item['upgrade_log']"></div>
|
||||||
</div>
|
</div>
|
||||||
</el-timeline-item>
|
</el-timeline-item>
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
<el-image class="w-[40px] h-[40px] mr-[10px]" :src="img(item.icon)" fit="contain">
|
<el-image class="w-[40px] h-[40px] mr-[10px]" :src="img(item.icon)" fit="contain">
|
||||||
<template #error>
|
<template #error>
|
||||||
<div class="image-slot">
|
<div class="image-slot">
|
||||||
<img class="w-[50px] h-[50px]" src="@/app/assets/images/index/app_default.png" />
|
<img class="w-[40px] h-[40px]" src="@/app/assets/images/index/app_default.png" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-image>
|
</el-image>
|
||||||
|
|||||||
@ -68,6 +68,7 @@
|
|||||||
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
||||||
<el-button type="primary" link @click="lockEvent(row.uid)" v-if="row.status">{{ t('lock') }}</el-button>
|
<el-button type="primary" link @click="lockEvent(row.uid)" v-if="row.status">{{ t('lock') }}</el-button>
|
||||||
<el-button type="primary" link @click="unlockEvent(row.uid)" v-else>{{ t('unlock') }}</el-button>
|
<el-button type="primary" link @click="unlockEvent(row.uid)" v-else>{{ t('unlock') }}</el-button>
|
||||||
|
<el-button type="primary" link @click="deleteEvent(row.uid)">{{ t('delete') }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<el-button link disabled>{{ t('adminDisabled') }}</el-button>
|
<el-button link disabled>{{ t('adminDisabled') }}</el-button>
|
||||||
@ -91,7 +92,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import { getUserList, lockUser, unlockUser } from '@/app/api/site'
|
import { getUserList, lockUser, unlockUser, deleteUser } from '@/app/api/site'
|
||||||
import EditUser from '@/app/views/auth/components/edit-user.vue'
|
import EditUser from '@/app/views/auth/components/edit-user.vue'
|
||||||
import { img } from '@/utils/common'
|
import { img } from '@/utils/common'
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox } from 'element-plus'
|
||||||
@ -198,6 +199,21 @@ const unlockEvent = (id: number) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deleteEvent = (uid: number) => {
|
||||||
|
ElMessageBox.confirm(t('userDeleteTips'), t('warning'),
|
||||||
|
{
|
||||||
|
confirmButtonText: t('confirm'),
|
||||||
|
cancelButtonText: t('cancel'),
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
deleteUser(uid).then(() => {
|
||||||
|
loadUserList()
|
||||||
|
}).catch(() => {
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|||||||
@ -75,7 +75,7 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog v-model="failReasonDialogVisible" :title="t('failReason')" width="60%">
|
<el-dialog v-model="failReasonDialogVisible" :title="t('failReason')" width="60%">
|
||||||
<el-scrollbar class="h-[60vh] w-full whitespace-pre p-[20px]">
|
<el-scrollbar class="h-[60vh] w-full whitespace-pre-wrap p-[20px]">
|
||||||
<div v-html="failReason"></div>
|
<div v-html="failReason"></div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="t('key')" prop="key">
|
<el-form-item :label="t('key')" prop="key">
|
||||||
<el-input v-model.trim="formData.key" clearable maxlength="40" show-word-limit :placeholder="t('keyPlaceholder')" class="input-width" />
|
<el-input v-model.trim="formData.key" clearable maxlength="40" show-word-limit :placeholder="t('keyPlaceholder')" class="input-width" />
|
||||||
|
<p class="form-tip">{{ t('keyFormatTips') }}</p>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="t('memo')">
|
<el-form-item :label="t('memo')">
|
||||||
<el-input v-model="formData.memo" type="textarea" clearable :placeholder="t('memoPlaceholder')" class="input-width" />
|
<el-input v-model="formData.memo" type="textarea" clearable :placeholder="t('memoPlaceholder')" class="input-width" />
|
||||||
@ -50,7 +51,17 @@ const formRules = computed(() => {
|
|||||||
{ required: true, message: t('namePlaceholder'), trigger: 'blur' }
|
{ required: true, message: t('namePlaceholder'), trigger: 'blur' }
|
||||||
],
|
],
|
||||||
key: [
|
key: [
|
||||||
{ required: true, message: t('keyPlaceholder'), trigger: 'blur' }
|
{ required: true, message: t('keyPlaceholder'), trigger: 'blur' },
|
||||||
|
{
|
||||||
|
validator: (rule: any, value: any, callback: any) => {
|
||||||
|
if (/^[a-zA-Z_]+$/.test(value)) {
|
||||||
|
callback()
|
||||||
|
} else {
|
||||||
|
callback(new Error(t('keyFormatTips')))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
],
|
],
|
||||||
data: [
|
data: [
|
||||||
{ required: true, message: t('dataPlaceholder'), trigger: 'blur' }
|
{ required: true, message: t('dataPlaceholder'), trigger: 'blur' }
|
||||||
|
|||||||
@ -87,15 +87,15 @@
|
|||||||
<el-input v-model.trim="item.title.text" :placeholder="t('activeCubeTitlePlaceholder')" clearable maxlength="4" show-word-limit/>
|
<el-input v-model.trim="item.title.text" :placeholder="t('activeCubeTitlePlaceholder')" clearable maxlength="4" show-word-limit/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('activeCubeSubTitleTextColor')" v-show="selectBlockStyle.value == 'style-3'">
|
<el-form-item :label="t('activeCubeSubTitleTextColor')" v-show="diyStore.editComponent.blockStyle.value == 'style-3'">
|
||||||
<el-color-picker v-model="item.title.textColor" show-alpha :predefine="diyStore.predefineColors" />
|
<el-color-picker v-model="item.title.textColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('activeCubeSubTitle')" v-if="selectBlockStyle.value != 'style-3'">
|
<el-form-item :label="t('activeCubeSubTitle')" v-if="diyStore.editComponent.blockStyle.value != 'style-3'">
|
||||||
<el-input v-model.trim="item.subTitle.text" :placeholder="t('activeCubeSubTitlePlaceholder')" clearable :maxlength="(selectBlockStyle.value != 'style-4' ? '6' : '4')" show-word-limit/>
|
<el-input v-model.trim="item.subTitle.text" :placeholder="t('activeCubeSubTitlePlaceholder')" clearable :maxlength="(diyStore.editComponent.blockStyle.value != 'style-4' ? '6' : '4')" show-word-limit/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<div v-show="selectBlockStyle.value == 'style-4'">
|
<div v-show="diyStore.editComponent.blockStyle.value == 'style-4'">
|
||||||
<el-form-item :label="t('activeCubeSubTitleTextColor')">
|
<el-form-item :label="t('activeCubeSubTitleTextColor')">
|
||||||
<el-color-picker v-model="item.subTitle.textColor" show-alpha :predefine="diyStore.predefineColors" />
|
<el-color-picker v-model="item.subTitle.textColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -111,7 +111,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-show="selectBlockStyle.value != 'style-4' && selectBlockStyle.value != 'style-3'">
|
<div v-show="diyStore.editComponent.blockStyle.value != 'style-4' && diyStore.editComponent.blockStyle.value != 'style-3'">
|
||||||
<el-form-item :label="t('activeCubeButton')">
|
<el-form-item :label="t('activeCubeButton')">
|
||||||
<el-input v-model.trim="item.moreTitle.text" :placeholder="t('activeCubeButtonPlaceholder')" clearable maxlength="3" show-word-limit/>
|
<el-input v-model.trim="item.moreTitle.text" :placeholder="t('activeCubeButtonPlaceholder')" clearable maxlength="3" show-word-limit/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|||||||
@ -70,14 +70,14 @@
|
|||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!--添加页面-->
|
<!--添加页面-->
|
||||||
<el-dialog v-model="dialogVisible" :title="t('addPageTips')" width="25%">
|
<el-dialog v-model="dialogVisible" :title="t('addPageTips')" width="350px">
|
||||||
|
|
||||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules">
|
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules">
|
||||||
<el-form-item :label="t('title')" prop="title">
|
<el-form-item :label="t('title')" prop="title">
|
||||||
<el-input v-model="formData.title" :placeholder="t('titlePlaceholder')" clearable maxlength="12" show-word-limit class="w-full" />
|
<el-input v-model="formData.title" :placeholder="t('titlePlaceholder')" clearable maxlength="12" show-word-limit class="w-full" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="t('typeName')" prop="type">
|
<el-form-item :label="t('typeName')" prop="type">
|
||||||
<el-select v-model="formData.type" :placeholder="t('pageTypePlaceholder')" class="w-full">
|
<el-select v-model="formData.type" :placeholder="t('pageTypePlaceholder')" class="!w-full">
|
||||||
<el-option v-for="(item, key) in pageType" :label="item.title" :value="key" :key="key"/>
|
<el-option v-for="(item, key) in pageType" :label="item.title" :value="key" :key="key"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|||||||
@ -17,7 +17,13 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column prop="key" :label="t('key')" min-width="80"/>
|
<el-table-column prop="key" :label="t('key')" min-width="120"/>
|
||||||
|
|
||||||
|
<el-table-column :label="t('type')" min-width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span>{{ row.info.type === 'app' ? t('app') : t('addon') }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column :label="t('operation')" fixed="right" align="right" min-width="160">
|
<el-table-column :label="t('operation')" fixed="right" align="right" min-width="160">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
|
|||||||
@ -129,7 +129,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column :label="t('operation')" align="right" fixed="right" width="230">
|
<el-table-column :label="t('operation')" align="right" fixed="right" width="120">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button v-for="(item, index) in operationBtn[row.status.toString()].value" :key="index + 'a'"
|
<el-button v-for="(item, index) in operationBtn[row.status.toString()].value" :key="index + 'a'"
|
||||||
@click="fnProcessing(operationBtn[row.status.toString()].clickArr[index], row)"
|
@click="fnProcessing(operationBtn[row.status.toString()].clickArr[index], row)"
|
||||||
@ -158,6 +158,19 @@
|
|||||||
<el-form-item :label="t('cashOutMethod')">
|
<el-form-item :label="t('cashOutMethod')">
|
||||||
<div class="input-width"> {{ Transfertype[cashOutInfo.transfer_type].name }} </div>
|
<div class="input-width"> {{ Transfertype[cashOutInfo.transfer_type].name }} </div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<template v-if="cashOutInfo.transfer_type == 'alipay'">
|
||||||
|
<el-form-item :label="t('alipayAccount')">
|
||||||
|
<div class="input-width"> {{ cashOutInfo.transfer_account }} </div>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
<template v-if="cashOutInfo.transfer_type == 'bank'">
|
||||||
|
<el-form-item :label="t('bankName')">
|
||||||
|
<div class="input-width"> {{ cashOutInfo.transfer_bank }} </div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="t('bankAccount')">
|
||||||
|
<div class="input-width"> {{ cashOutInfo.transfer_account }} </div>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
<el-form-item :label="t('applicationForWithdrawalAmount')">
|
<el-form-item :label="t('applicationForWithdrawalAmount')">
|
||||||
<div class="input-width"> {{ cashOutInfo.apply_money }} </div>
|
<div class="input-width"> {{ cashOutInfo.apply_money }} </div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
<span :class="['px-[10px] cursor-pointer h-[35px] leading-[35px] inline-block', {'text-[var(--el-color-primary)]': params.app == item.key}]" @click="cutAppFn(item.key)" v-for="(item,index) in addonList" :key="index">{{item.title}}</span>
|
<span :class="['px-[10px] cursor-pointer h-[35px] leading-[35px] inline-block', {'text-[var(--el-color-primary)]': params.app == item.key}]" @click="cutAppFn(item.key)" v-for="(item,index) in addonList" :key="index">{{item.title}}</span>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
<el-input v-model="params.keywords" class="!w-[300px] !h-[34px]" placeholder="请输入要搜索的站点名称" @keyup.enter.native="getHomeSiteFn()">
|
<el-input v-model="params.keywords" class="!w-[300px] !h-[34px]" placeholder="请输入要搜索的站点名称/编号" @keyup.enter.native="getHomeSiteFn()">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<el-icon @click.stop="getHomeSiteFn()" class="cursor-pointer">
|
<el-icon @click.stop="getHomeSiteFn()" class="cursor-pointer">
|
||||||
<Search />
|
<Search />
|
||||||
@ -95,7 +95,7 @@
|
|||||||
:class="{'bg-[#F6F7FF] border-[#466CEA]': createSiteData.formData.group_id == item.group_id ,'ml-[20px]': index > 0, ' ml-[10px]': index == 0, 'mr-[10px]': (siteGroup.length-1) == index }"
|
:class="{'bg-[#F6F7FF] border-[#466CEA]': createSiteData.formData.group_id == item.group_id ,'ml-[20px]': index > 0, ' ml-[10px]': index == 0, 'mr-[10px]': (siteGroup.length-1) == index }"
|
||||||
@click="createSiteData.formData.group_id = item.group_id"
|
@click="createSiteData.formData.group_id = item.group_id"
|
||||||
>
|
>
|
||||||
<div class="w-[140px] h-[40px] truncate text-white text-[16px] text-center leading-[40px] creatBg relative -left-[1px] -top-[2px]">
|
<div class="w-[140px] h-[40px] px-[15px] truncate text-white text-[16px] text-center leading-[40px] creatBg relative -left-[1px] -top-[2px]">
|
||||||
{{ item.site_group.group_name }}
|
{{ item.site_group.group_name }}
|
||||||
</div>
|
</div>
|
||||||
<el-scrollbar class="flex pb-[20px] pt-[4px] box-border !h-[260px]">
|
<el-scrollbar class="flex pb-[20px] pt-[4px] box-border !h-[260px]">
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
{{ t('buyLabel') }}
|
{{ t('buyLabel') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-button type="primary" round @click="handleCloudBuild" :loading="cloudBuildRef?.loading">{{ t('cloudBuild') }}</el-button>
|
<el-button type="primary" round @click="handleCloudBuild" :loading="cloudBuildRef?.loading" :disabled="authLoading">{{ t('cloudBuild') }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@ -42,12 +42,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-image>
|
</el-image>
|
||||||
<div class="flex flex-col justify-center pl-[20px] font-500 text-[13px]">
|
<div class="flex-1 w-0 flex flex-col justify-center pl-[20px] font-500 text-[13px]">
|
||||||
<div class="w-[236px] truncate leading-[18px]">{{ row.title }}</div>
|
<div class="w-[236px] truncate leading-[18px]">{{ row.title }}</div>
|
||||||
<div class="w-[236px] truncate leading-[18px] mt-[6px]" v-if="row.install_info && Object.keys(row.install_info)?.length">{{ row.install_info.version }}</div>
|
<div class="w-[236px] truncate leading-[18px] mt-[6px]" v-if="row.install_info && Object.keys(row.install_info)?.length">{{ row.install_info.version }}</div>
|
||||||
<div class="w-[236px] truncate leading-[18px] mt-[6px]" v-else>{{ row.version }}</div>
|
<div class="w-[236px] truncate leading-[18px] mt-[6px]" v-else>{{ row.version }}</div>
|
||||||
<div class="mt-[3px]" v-if="row.install_info && Object.keys(row.install_info)?.length && row.install_info.version != row.version">
|
<div class="mt-[3px] flex flex-nowrap">
|
||||||
<el-tag type="danger" size="small">{{ t('newVersion') }}{{ row.version }}</el-tag>
|
<el-tag type="danger" size="small" v-if="row.install_info && Object.keys(row.install_info)?.length && row.install_info.version != row.version">{{ t('newVersion') }}{{ row.version }}</el-tag>
|
||||||
|
<el-tooltip v-if="versionJudge(row)" effect="dark" content="该插件与框架版本不兼容,可能存在未知问题" placement="top-start" >
|
||||||
|
<el-tag type="info" size="small" class="ml-[3px]">该插件与框架版本不兼容,可能存在未知问题</el-tag>
|
||||||
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -376,6 +379,7 @@ import { t } from '@/lang'
|
|||||||
import { getAddonLocal, uninstallAddon, installAddon, preInstallCheck, cloudInstallAddon, getAddonInstalltask, getAddonCloudInstallLog, preUninstallCheck, cancelInstall } from '@/app/api/addon'
|
import { getAddonLocal, uninstallAddon, installAddon, preInstallCheck, cloudInstallAddon, getAddonInstalltask, getAddonCloudInstallLog, preUninstallCheck, cancelInstall } from '@/app/api/addon'
|
||||||
import { deleteAddonDevelop } from '@/app/api/tools'
|
import { deleteAddonDevelop } from '@/app/api/tools'
|
||||||
import { downloadVersion, getAuthInfo, setAuthInfo } from '@/app/api/module'
|
import { downloadVersion, getAuthInfo, setAuthInfo } from '@/app/api/module'
|
||||||
|
import { getVersions } from '@/app/api/auth'
|
||||||
import { ElMessage, ElMessageBox, ElNotification, FormInstance, FormRules } from 'element-plus'
|
import { ElMessage, ElMessageBox, ElNotification, FormInstance, FormRules } from 'element-plus'
|
||||||
import 'vue-web-terminal/lib/theme/dark.css'
|
import 'vue-web-terminal/lib/theme/dark.css'
|
||||||
import { Terminal, TerminalFlash } from 'vue-web-terminal'
|
import { Terminal, TerminalFlash } from 'vue-web-terminal'
|
||||||
@ -397,6 +401,11 @@ const installAfterTips = ref<string[]>([])
|
|||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const unloadHintDialog = ref(false)
|
const unloadHintDialog = ref(false)
|
||||||
const terminalRef = ref(null)
|
const terminalRef = ref(null)
|
||||||
|
const frameworkVersion = ref('')
|
||||||
|
|
||||||
|
getVersions().then(res => {
|
||||||
|
frameworkVersion.value = res.data.version.version
|
||||||
|
})
|
||||||
|
|
||||||
const currDownData = ref()
|
const currDownData = ref()
|
||||||
const downEventHintFn = () => {
|
const downEventHintFn = () => {
|
||||||
@ -902,6 +911,14 @@ const deleteAddonFn = (key: string) => {
|
|||||||
})
|
})
|
||||||
}).catch(() => { })
|
}).catch(() => { })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const versionJudge = (row: any) => {
|
||||||
|
if (!row.support_version) return true
|
||||||
|
const supportVersionApp = row.support_version.split('.')
|
||||||
|
const frameworkVersionArr = frameworkVersion.value.split('.')
|
||||||
|
if (parseFloat(`${supportVersionApp[0]}.${supportVersionApp[1]}`) < parseFloat(`${frameworkVersionArr[0]}.${frameworkVersionArr[1]}`)) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form :model="formData" :rules="formRules" class="page-form" ref="formRef">
|
<el-form :model="formData" :rules="formRules" class="page-form" ref="formRef">
|
||||||
<el-form-item :label="t('continueSign')" prop="continue_sign">
|
<el-form-item :label="t('continueSign')" prop="continue_sign">
|
||||||
<el-input class="input-width" v-model.trim="formData.continue_sign" clearable /><span class="ml-[10px]">{{ t('day') }}</span>
|
<el-input class="input-width" v-model.trim="formData.continue_sign" :maxlength="5" clearable /><span class="ml-[10px]">{{ t('day') }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="t('continueSign')" >
|
<el-form-item :label="t('continueSign')" >
|
||||||
<div>
|
<div class="flex-1">
|
||||||
<div v-for="(item,index) in gifts" :key="index" class="mb-[15px]">
|
<div v-for="(item,index) in gifts" :key="index" class="mb-[15px]">
|
||||||
<component :is="item.component" v-model="formData[item.key]" ref="giftRefs" v-if="item.component" />
|
<component :is="item.component" v-model="formData[item.key]" ref="giftRefs" v-if="item.component" />
|
||||||
</div>
|
</div>
|
||||||
@ -15,7 +15,7 @@
|
|||||||
<el-radio class="mb-[15px]" v-model="formData.receive_limit" :label="1" @change="radioChange($event, 1)">{{ t('noLimit') }}</el-radio>
|
<el-radio class="mb-[15px]" v-model="formData.receive_limit" :label="1" @change="radioChange($event, 1)">{{ t('noLimit') }}</el-radio>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<el-radio class="!mr-[15px]" v-model="formData.receive_limit" :label="2" @change="radioChange($event, 2)">{{ t('everyOneLimit') }}</el-radio>
|
<el-radio class="!mr-[15px]" v-model="formData.receive_limit" :label="2" @change="radioChange($event, 2)">{{ t('everyOneLimit') }}</el-radio>
|
||||||
<el-input class="input-width" v-model="formData.receive_num" clearable /><span class="ml-[10px]">{{ t('time') }}</span>
|
<el-input class="input-width" v-model="formData.receive_num" :maxlength="5" clearable /><span class="ml-[10px]">{{ t('time') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -76,18 +76,26 @@ getGiftDict().then(({ data }) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const formRef = ref(null)
|
const formRef = ref(null)
|
||||||
|
// 正则表达式
|
||||||
|
const regExp = {
|
||||||
|
required: /[\S]+/,
|
||||||
|
number: /^\d{0,10}$/,
|
||||||
|
digit: /^\d{0,10}(.?\d{0,2})$/,
|
||||||
|
special: /^\d{0,10}(.?\d{0,3})$/
|
||||||
|
}
|
||||||
// 表单验证规则
|
// 表单验证规则
|
||||||
const formRules = reactive<FormRules>({
|
const formRules = reactive<FormRules>({
|
||||||
continue_sign: [
|
continue_sign: [
|
||||||
{ required: true, message: t('continueSignPlaceholder'), trigger: 'blur' },
|
{ required: true, message: t('continueSignPlaceholder'), trigger: 'blur' },
|
||||||
{
|
{
|
||||||
validator: (rule: any, value: any, callback: Function) => {
|
|
||||||
if (!Test.digits(formData.value.continue_sign)) {
|
validator: (rule: any, value: any, callback: any) => {
|
||||||
callback('连续签到格式错误')
|
if (isNaN(value) || !regExp.number.test(value)) {
|
||||||
} else if (formData.value.continue_sign <= 0) {
|
callback('连续签到天数格式错误')
|
||||||
callback('连续签到不能小于等于0')
|
} else if (value <=0) {
|
||||||
} else {
|
callback('连续签到天数不能小于等于0')
|
||||||
callback()
|
} else{
|
||||||
|
callback();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
trigger: 'blur'
|
trigger: 'blur'
|
||||||
@ -101,7 +109,7 @@ const formRules = reactive<FormRules>({
|
|||||||
if (Test.empty(formData.value.receive_num)) {
|
if (Test.empty(formData.value.receive_num)) {
|
||||||
callback('请输入限领次数')
|
callback('请输入限领次数')
|
||||||
}
|
}
|
||||||
if (!Test.digits(formData.value.receive_num)) {
|
if (isNaN(formData.value.receive_num) || !regExp.number.test(formData.value.receive_num)) {
|
||||||
callback('限领次数格式错误')
|
callback('限领次数格式错误')
|
||||||
}
|
}
|
||||||
if (formData.value.receive_num <= 0) {
|
if (formData.value.receive_num <= 0) {
|
||||||
|
|||||||
@ -11,10 +11,10 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('signPeriod')" v-if="formData.is_use">
|
<el-form-item :label="t('signPeriod')" v-if="formData.is_use">
|
||||||
<el-input-number v-model="formData.sign_period" clearable class="input-width" controls-position="right" /><span class="ml-[10px]">天</span>
|
<el-input-number v-model="formData.sign_period" :min="0" :precision="0" clearable class="input-width" controls-position="right" /><span class="ml-[10px]">天</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('daySignAward')" prop="formData.day_award" v-if="formData.is_use">
|
<el-form-item :label="t('daySignAward')" prop="day_award" v-if="formData.is_use">
|
||||||
<div v-for="(item, index) in daySignAwardText" :key="index">
|
<div v-for="(item, index) in daySignAwardText" :key="index">
|
||||||
<span v-if="item.is_use == '1'">{{ item.content }} </span>
|
<span v-if="item.is_use == '1'">{{ item.content }} </span>
|
||||||
</div>
|
</div>
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<div class="form-tip">{{ t('daySignAwardTip') }}</div>
|
<div class="form-tip">{{ t('daySignAwardTip') }}</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('continueSignAward')" prop="formData.continue_award" v-if="formData.is_use">
|
<el-form-item :label="t('continueSignAward')" prop="continue_award" v-if="formData.is_use">
|
||||||
<div>
|
<div>
|
||||||
<div class="form-tip">{{ t('continueSignAwardTipTop') }}</div>
|
<div class="form-tip">{{ t('continueSignAwardTipTop') }}</div>
|
||||||
<div class="mt-[10px]">
|
<div class="mt-[10px]">
|
||||||
@ -68,9 +68,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('ruleExplain')" prop="formData.rule_explain" v-if="formData.is_use">
|
<el-form-item :label="t('ruleExplain')" prop="rule_explain" v-if="formData.is_use">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<el-input v-model="formData.rule_explain" :placeholder="t('ruleExplainTip')" type="textarea" rows="5" class="textarea-width" clearable />
|
<el-input v-model="formData.rule_explain" :placeholder="t('ruleExplainTip')" type="textarea" maxlength="500" show-word-limit rows="5" class="textarea-width" clearable />
|
||||||
<el-button class="ml-[20px]" type="primary" @click="defaultExplainEvent()" plain>{{ t('useDefaultExplain') }}</el-button>
|
<el-button class="ml-[20px]" type="primary" @click="defaultExplainEvent()" plain>{{ t('useDefaultExplain') }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -89,7 +89,7 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 连签奖励 -->
|
<!-- 连签奖励 -->
|
||||||
<el-dialog v-model="continueSignDialog" :title="t('continueSignTitle')" width="1200px" :destroy-on-close="true" v-if="formData.is_use">
|
<el-dialog v-model="continueSignDialog" :title="t('continueSignTitle')" width="800px" :destroy-on-close="true" v-if="formData.is_use">
|
||||||
<sign-continue ref="continueRef" v-model="continue_award" />
|
<sign-continue ref="continueRef" v-model="continue_award" />
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
@ -134,7 +134,10 @@ let editIndex = 0 // 连签奖励修改下标
|
|||||||
const formRules = reactive<FormRules>({
|
const formRules = reactive<FormRules>({
|
||||||
sign_period: [
|
sign_period: [
|
||||||
{ required: true, message: t('signPeriodTip'), trigger: 'blur' }
|
{ required: true, message: t('signPeriodTip'), trigger: 'blur' }
|
||||||
]
|
],
|
||||||
|
day_award: [
|
||||||
|
{ required: true, message: t('daySignAwardPlaceholder'), trigger: 'change' }
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<el-checkbox v-model="formData.is_use" :true-label="1" :false-label="0" label="" size="large" />
|
<el-checkbox v-model="formData.is_use" :true-label="1" :false-label="0" label="" size="large" />
|
||||||
<span class="ml-[10px] el-form-item__label">送</span>
|
<span class="ml-[10px] el-form-item__label">送</span>
|
||||||
<div class="w-[70px]">
|
<div class="w-[70px]">
|
||||||
<el-input v-model.trim="formData.money" clearable />
|
<el-input v-model.trim="formData.money" :maxlength="5" clearable />
|
||||||
</div>
|
</div>
|
||||||
<span class="ml-[15px] el-form-item__label">元红包</span>
|
<span class="ml-[15px] el-form-item__label">元红包</span>
|
||||||
</div>
|
</div>
|
||||||
@ -33,26 +33,31 @@ const formData = ref({
|
|||||||
money: ''
|
money: ''
|
||||||
})
|
})
|
||||||
const formRef = ref(null)
|
const formRef = ref(null)
|
||||||
|
// 正则表达式
|
||||||
|
const regExp = {
|
||||||
|
required: /[\S]+/,
|
||||||
|
number: /^\d{0,10}$/,
|
||||||
|
digit: /^\d{0,10}(.?\d{0,2})$/,
|
||||||
|
special: /^\d{0,10}(.?\d{0,3})$/
|
||||||
|
}
|
||||||
const formRules = reactive<FormRules>({
|
const formRules = reactive<FormRules>({
|
||||||
money: [
|
money: [
|
||||||
{
|
{
|
||||||
validator: (rule: any, value: any, callback: any) => {
|
validator: (rule: any, value: any, callback: any) => {
|
||||||
if (formData.value.is_use) {
|
if (formData.value.is_use) {
|
||||||
if (Test.empty(formData.value.money)) {
|
if (Test.empty(value)) {
|
||||||
callback('请输入红包金额')
|
callback('请输入红包金额')
|
||||||
}
|
}else if (isNaN(value) || !regExp.digit.test(value)) {
|
||||||
if (!Test.amount(formData.value.money)) {
|
|
||||||
callback('红包金额格式错误')
|
callback('红包金额格式错误')
|
||||||
}
|
}else if (value <= 0) {
|
||||||
if (formData.value.money <= 0) {
|
|
||||||
callback('红包金额不能小于等于0')
|
callback('红包金额不能小于等于0')
|
||||||
}
|
}
|
||||||
callback()
|
callback()
|
||||||
} else {
|
} else {
|
||||||
callback()
|
callback()
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
trigger: 'blur'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
@ -32,26 +32,32 @@ const formData = ref({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const formRef = ref(null)
|
const formRef = ref(null)
|
||||||
|
// 正则表达式
|
||||||
|
const regExp = {
|
||||||
|
required: /[\S]+/,
|
||||||
|
number: /^\d{0,10}$/,
|
||||||
|
digit: /^\d{0,10}(.?\d{0,2})$/,
|
||||||
|
special: /^\d{0,10}(.?\d{0,3})$/
|
||||||
|
}
|
||||||
const formRules = reactive<FormRules>({
|
const formRules = reactive<FormRules>({
|
||||||
num: [
|
num: [
|
||||||
{
|
{
|
||||||
validator: (rule: any, value: any, callback: Function) => {
|
validator: (rule: any, value: any, callback: any) => {
|
||||||
if (formData.value.is_use) {
|
if (formData.value.is_use) {
|
||||||
if (Test.empty(formData.value.num)) {
|
if (value.length == 0) {
|
||||||
callback('请输入发放积分数量')
|
callback('请输入积分数量')
|
||||||
}
|
} else if (isNaN(value) || !regExp.number.test(value)) {
|
||||||
if (!Test.digits(formData.value.num)) {
|
|
||||||
callback('积分数量格式错误')
|
callback('积分数量格式错误')
|
||||||
}
|
} else if (value <=0) {
|
||||||
if (formData.value.num <= 0) {
|
|
||||||
callback('积分数量不能小于等于0')
|
callback('积分数量不能小于等于0')
|
||||||
|
} else{
|
||||||
|
callback();
|
||||||
}
|
}
|
||||||
callback()
|
|
||||||
} else {
|
} else {
|
||||||
callback()
|
callback()
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
trigger: 'blur'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
@ -66,14 +66,14 @@
|
|||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!--添加海报-->
|
<!--添加海报-->
|
||||||
<el-dialog v-model="dialogVisible" :title="t('addPosterTitle')" width="25%">
|
<el-dialog v-model="dialogVisible" :title="t('addPosterTitle')" width="350px">
|
||||||
|
|
||||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules">
|
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules">
|
||||||
<el-form-item :label="t('posterName')" prop="name">
|
<el-form-item :label="t('posterName')" prop="name">
|
||||||
<el-input v-model="formData.name" :placeholder="t('posterNamePlaceholder')" clearable maxlength="12" show-word-limit class="w-full" />
|
<el-input v-model="formData.name" :placeholder="t('posterNamePlaceholder')" clearable maxlength="12" show-word-limit class="w-full" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="t('posterType')" prop="type">
|
<el-form-item :label="t('posterType')" prop="type">
|
||||||
<el-select v-model="formData.type" :placeholder="t('posterTypePlaceholder')" class="w-full">
|
<el-select v-model="formData.type" :placeholder="t('posterTypePlaceholder')" class="!w-full">
|
||||||
<el-option v-for="item in posterType" :label="item.name" :value="item.type" :key="item.type"/>
|
<el-option v-for="item in posterType" :label="item.name" :value="item.type" :key="item.type"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|||||||
@ -116,4 +116,8 @@ const back = () => {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss">
|
||||||
|
.edui-default .edui-editor{
|
||||||
|
z-index: 1 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,21 +1,29 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog v-model="showDialog" :title="t('addUser')" width="750px" :destroy-on-close="true">
|
<el-dialog v-model="showDialog" :title="formData.uid ? t('updateUser') : t('addUser')" width="750px" :destroy-on-close="true">
|
||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
<div class="max-h-[60vh]">
|
<div class="max-h-[60vh]">
|
||||||
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" autocomplete="off" v-loading="loading">
|
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" autocomplete="off" v-loading="loading">
|
||||||
<el-form-item :label="t('username')" prop="username">
|
<el-form-item :label="t('username')" prop="username">
|
||||||
<el-input v-model="formData.username" clearable :placeholder="t('usernamePlaceholder')" class="input-width" :readonly="real_name_input" @click="real_name_input = false" @blur="real_name_input = true" />
|
<el-input v-model="formData.username" clearable :placeholder="t('usernamePlaceholder')" class="input-width" :readonly="formData.uid" :disabled="formData.uid" @click="realnameInput = false" @blur="realnameInput = true" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="t('headImg')">
|
||||||
|
<upload-image v-model="formData.head_img" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="t('userRealName')" prop="real_name">
|
||||||
|
<el-input v-model.trim="formData.real_name" :placeholder="t('userRealNamePlaceholder')" :readonly="realnameInput" @click="realnameInput = false" @blur="realnameInput = true" clearable class="input-width" maxlength="10" show-word-limit />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('password')" prop="password">
|
<el-form-item :label="t('password')" prop="password">
|
||||||
<el-input v-model="formData.password" clearable :placeholder="t('passwordPlaceholder')" class="input-width" :show-password="true" type="password" :readonly="password_input" @click="password_input = false" @blur="password_input = true" />
|
<el-input v-model="formData.password" clearable :placeholder="t('passwordPlaceholder')" class="input-width" :show-password="true" type="password" :readonly="passwordInput" @click="passwordInput = false" @blur="passwordInput = true" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('confirmPassword')" prop="confirm_password">
|
<el-form-item :label="t('confirmPassword')" prop="confirm_password">
|
||||||
<el-input v-model="formData.confirm_password" :placeholder="t('confirmPasswordPlaceholder')" type="password" :show-password="true" clearable class="input-width" :readonly="confirm_password_input" @click="confirm_password_input = false" @blur="confirm_password_input = true" />
|
<el-input v-model="formData.confirm_password" :placeholder="t('confirmPasswordPlaceholder')" type="password" :show-password="true" clearable class="input-width" :readonly="confirmPasswordInput" @click="confirmPasswordInput = false" @blur="confirmPasswordInput = true" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="t('userCreateSiteLimit')" v-if="Object.keys(siteGroup).length" prop="create_site_limit">
|
<el-form-item :label="t('userCreateSiteLimit')" v-if="!formData.uid && Object.keys(siteGroup).length" prop="create_site_limit">
|
||||||
<div>
|
<div>
|
||||||
<div>{{ t('siteGroup') }}</div>
|
<div>{{ t('siteGroup') }}</div>
|
||||||
<el-checkbox-group v-model="formData.group_ids" @change="groupSelect">
|
<el-checkbox-group v-model="formData.group_ids" @change="groupSelect">
|
||||||
@ -60,75 +68,81 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue'
|
import {computed, ref} from 'vue'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
import { FormInstance } from 'element-plus'
|
import { FormInstance } from 'element-plus'
|
||||||
import { getSiteGroupAll } from '@/app/api/site'
|
import { getSiteGroupAll } from '@/app/api/site'
|
||||||
import { addUser } from '@/app/api/user'
|
import { addUser, getUserInfo, editUser } from '@/app/api/user'
|
||||||
import Test from '@/utils/test'
|
import Test from '@/utils/test'
|
||||||
|
|
||||||
const showDialog = ref(false)
|
const showDialog = ref(false)
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
|
uid: 0,
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
|
head_img: '',
|
||||||
|
real_name: '',
|
||||||
confirm_password: '',
|
confirm_password: '',
|
||||||
create_site_limit: [],
|
create_site_limit: [],
|
||||||
group_ids: []
|
group_ids: []
|
||||||
})
|
})
|
||||||
const siteGroup = ref({})
|
const siteGroup = ref({})
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
const formRules = ref({
|
const formRules = computed(() => {
|
||||||
username: [
|
return {
|
||||||
{ required: true, message: t('usernamePlaceholder'), trigger: 'blur' }
|
username: [
|
||||||
],
|
{ required: true, message: t('usernamePlaceholder'), trigger: 'blur' }
|
||||||
password: [
|
],
|
||||||
{ required: true, message: t('passwordPlaceholder'), trigger: 'blur' }
|
password: [
|
||||||
],
|
{ required: formData.value.uid == 0, message: t('passwordPlaceholder'), trigger: 'blur' }
|
||||||
real_name: [
|
],
|
||||||
{ required: true, message: t('userRealNamePlaceholder'), trigger: 'blur' }
|
real_name: [
|
||||||
],
|
{ required: true, message: t('userRealNamePlaceholder'), trigger: 'blur' }
|
||||||
confirm_password: [
|
],
|
||||||
{ required: true, message: t('confirmPasswordPlaceholder'), trigger: 'blur' },
|
confirm_password: [
|
||||||
{
|
{ required: formData.value.uid == 0, message: t('confirmPasswordPlaceholder'), trigger: 'blur' },
|
||||||
validator: (rule: any, value: string, callback: any) => {
|
{
|
||||||
if (value != formData.value.password) callback(new Error(t('confirmPasswordError')))
|
validator: (rule: any, value: string, callback: any) => {
|
||||||
else callback()
|
if (value != formData.value.password) callback(new Error(t('confirmPasswordError')))
|
||||||
},
|
else callback()
|
||||||
trigger: 'blur'
|
},
|
||||||
}
|
trigger: 'blur'
|
||||||
],
|
|
||||||
create_site_limit: [
|
|
||||||
{
|
|
||||||
validator: (rule: any, value: string, callback: any) => {
|
|
||||||
let verify = true
|
|
||||||
for (let i = 0; i < formData.value.create_site_limit.length; i++) {
|
|
||||||
const item = formData.value.create_site_limit[i]
|
|
||||||
if (Test.empty(item.num)) {
|
|
||||||
callback(t('siteNumPlaceholder'))
|
|
||||||
verify = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if (item.num < 1) {
|
|
||||||
callback(t('siteNumCannotLtOne'))
|
|
||||||
verify = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if (Test.empty(item.month)) {
|
|
||||||
callback(t('siteMonthPlaceholder'))
|
|
||||||
verify = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if (item.month < 0) {
|
|
||||||
callback(t('siteMonthCannotLtOne'))
|
|
||||||
verify = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (verify) callback()
|
|
||||||
}
|
}
|
||||||
}
|
],
|
||||||
]
|
create_site_limit: [
|
||||||
|
{
|
||||||
|
validator: (rule: any, value: string, callback: any) => {
|
||||||
|
if (formData.value.uid) callback()
|
||||||
|
let verify = true
|
||||||
|
for (let i = 0; i < formData.value.create_site_limit.length; i++) {
|
||||||
|
const item = formData.value.create_site_limit[i]
|
||||||
|
if (Test.empty(item.num)) {
|
||||||
|
callback(t('siteNumPlaceholder'))
|
||||||
|
verify = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (item.num < 1) {
|
||||||
|
callback(t('siteNumCannotLtOne'))
|
||||||
|
verify = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (Test.empty(item.month)) {
|
||||||
|
callback(t('siteMonthPlaceholder'))
|
||||||
|
verify = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (item.month < 0) {
|
||||||
|
callback(t('siteMonthCannotLtOne'))
|
||||||
|
verify = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (verify) callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
getSiteGroupAll().then(({ data }) => {
|
getSiteGroupAll().then(({ data }) => {
|
||||||
@ -141,7 +155,14 @@ getSiteGroupAll().then(({ data }) => {
|
|||||||
|
|
||||||
const setFormData = (uid: number = 0) => {
|
const setFormData = (uid: number = 0) => {
|
||||||
if (uid) {
|
if (uid) {
|
||||||
|
getUserInfo(uid).then(({ data }) => {
|
||||||
|
formData.value.uid = data.uid
|
||||||
|
formData.value.username = data.username
|
||||||
|
formData.value.real_name = data.real_name
|
||||||
|
formData.value.head_img = data.head_img
|
||||||
|
loading.value = false
|
||||||
|
showDialog.value = true
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
showDialog.value = true
|
showDialog.value = true
|
||||||
@ -172,7 +193,7 @@ const confirm = async (formEl: FormInstance | undefined) => {
|
|||||||
await formEl.validate(async (valid) => {
|
await formEl.validate(async (valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
const save = addUser
|
const save = formData.value.uid ? editUser : addUser
|
||||||
|
|
||||||
save(formData.value).then(() => {
|
save(formData.value).then(() => {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
@ -185,9 +206,9 @@ const confirm = async (formEl: FormInstance | undefined) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const real_name_input = ref(true)
|
const realnameInput = ref(true)
|
||||||
const password_input = ref(true)
|
const passwordInput = ref(true)
|
||||||
const confirm_password_input = ref(true)
|
const confirmPasswordInput = ref(true)
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
showDialog,
|
showDialog,
|
||||||
|
|||||||
@ -81,7 +81,7 @@
|
|||||||
|
|
||||||
<div class="fixed-footer-wrap">
|
<div class="fixed-footer-wrap">
|
||||||
<div class="fixed-footer">
|
<div class="fixed-footer">
|
||||||
<el-button type="primary" @click="confirm(formRef)" v-loading="saveLoading">{{ t('save') }}</el-button>
|
<el-button type="primary" @click="confirm(formRef)">{{ t('save') }}</el-button>
|
||||||
<el-button @click="back()">{{ t('cancel') }}</el-button>
|
<el-button @click="back()">{{ t('cancel') }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
|
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
|
||||||
<el-form :inline="true" :model="siteTableData.searchParam" ref="searchFormRef">
|
<el-form :inline="true" :model="siteTableData.searchParam" ref="searchFormRef">
|
||||||
<el-form-item :label="t('siteName')" prop="keywords">
|
<el-form-item :label="t('siteInfo')" prop="keywords">
|
||||||
<el-input v-model="siteTableData.searchParam.keywords" :placeholder="t('siteNamePlaceholder')" />
|
<el-input v-model="siteTableData.searchParam.keywords" :placeholder="t('siteNamePlaceholder')" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@ -157,6 +157,7 @@ import { useRouter, useRoute } from 'vue-router'
|
|||||||
import EditSite from '@/app/views/site/components/edit-site.vue'
|
import EditSite from '@/app/views/site/components/edit-site.vue'
|
||||||
import { getInstalledAddonList } from '@/app/api/addon'
|
import { getInstalledAddonList } from '@/app/api/addon'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
|
import {deleteUser} from "@/app/api/user";
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const pageName = route.meta.title
|
const pageName = route.meta.title
|
||||||
@ -308,8 +309,16 @@ const toSiteLink = (siteId:number = 0) => {
|
|||||||
|
|
||||||
const openClose = (i, site_id) => {
|
const openClose = (i, site_id) => {
|
||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
closeSite({ site_id }).then(res => {
|
ElMessageBox.confirm(t('closeSiteTips'), t('warning'),
|
||||||
loadSiteList()
|
{
|
||||||
|
confirmButtonText: t('confirm'),
|
||||||
|
cancelButtonText: t('cancel'),
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
closeSite({ site_id }).then(res => {
|
||||||
|
loadSiteList()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (i == 3) {
|
if (i == 3) {
|
||||||
|
|||||||
@ -65,10 +65,11 @@
|
|||||||
{{ row.last_ip || '' }}
|
{{ row.last_ip || '' }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="t('operation')" align="right" fixed="right" width="200">
|
<el-table-column :label="t('operation')" align="right" fixed="right" width="180">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button type="primary" link @click="detailEvent(row.uid)">{{ t('detail') }}</el-button>
|
<el-button type="primary" link @click="detailEvent(row.uid)">{{ t('detail') }}</el-button>
|
||||||
<template v-if="!row.is_super_admin">
|
<template v-if="!row.is_super_admin">
|
||||||
|
<el-button type="primary" link @click="editEvent(row.uid)" >{{ t('edit') }}</el-button>
|
||||||
<el-button type="primary" link @click="detailEvent(row.uid, 'userCreateSiteLimit')" >{{ t('userCreateSiteLimit') }}</el-button>
|
<el-button type="primary" link @click="detailEvent(row.uid, 'userCreateSiteLimit')" >{{ t('userCreateSiteLimit') }}</el-button>
|
||||||
<el-button type="primary" link @click="deleteEvent(row.uid)" >{{ t('delete') }}</el-button>
|
<el-button type="primary" link @click="deleteEvent(row.uid)" >{{ t('delete') }}</el-button>
|
||||||
</template>
|
</template>
|
||||||
@ -157,6 +158,14 @@ const detailEvent = (uid: number, tab: string = '') => {
|
|||||||
router.push({ path: '/admin/site/user_info', query: { uid, tab } })
|
router.push({ path: '/admin/site/user_info', query: { uid, tab } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑用户
|
||||||
|
* @param uid
|
||||||
|
*/
|
||||||
|
const editEvent = (uid: number) => {
|
||||||
|
userEditRef.value.setFormData(uid)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除用户
|
* 删除用户
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -22,6 +22,30 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-alert>
|
</el-alert>
|
||||||
|
|
||||||
|
<el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never">
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<el-form :inline="true" :model="cronTableData.searchParam" ref="searchFormRef">
|
||||||
|
<el-form-item :label="t('title')" prop="key">
|
||||||
|
<el-select v-model="cronTableData.searchParam.key" placeholder="全部" filterable remote clearable :remote-method="getAddonDevelopFn">
|
||||||
|
<el-option label="全部" value="all" />
|
||||||
|
<el-option v-for="item in templateList" :key="item.key" :label="item.name" :value="item.key" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="t('status')" prop="status">
|
||||||
|
<el-select v-model="cronTableData.searchParam.status" placeholder="全部" filterable remote clearable :remote-method="getAddonDevelopFn">
|
||||||
|
<el-option label="全部" value="all" />
|
||||||
|
<el-option label="启用" value="1" />
|
||||||
|
<el-option label="关闭" value="0" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="loadCronList()">{{ t('search') }}</el-button>
|
||||||
|
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
<div class="mt-[20px]">
|
<div class="mt-[20px]">
|
||||||
<el-table :data="cronTableData.data" size="large" v-loading="cronTableData.loading">
|
<el-table :data="cronTableData.data" size="large" v-loading="cronTableData.loading">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
@ -124,9 +148,8 @@ const cronTableData = reactive({
|
|||||||
loading: true,
|
loading: true,
|
||||||
data: [],
|
data: [],
|
||||||
searchParam: {
|
searchParam: {
|
||||||
title: '',
|
|
||||||
type: '',
|
type: '',
|
||||||
last_time: ''
|
status: 'all'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const templateList = ref([])
|
const templateList = ref([])
|
||||||
@ -134,6 +157,12 @@ const date_type = ref([])
|
|||||||
const week_list = ref([])
|
const week_list = ref([])
|
||||||
const searchFormRef = ref<FormInstance>()
|
const searchFormRef = ref<FormInstance>()
|
||||||
|
|
||||||
|
const resetForm = (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return
|
||||||
|
formEl.resetFields()
|
||||||
|
loadCronList()
|
||||||
|
}
|
||||||
|
|
||||||
const setTypeList = async () => {
|
const setTypeList = async () => {
|
||||||
templateList.value = await (await getCronTemplate()).data
|
templateList.value = await (await getCronTemplate()).data
|
||||||
date_type.value = await (await getCronDateType()).data
|
date_type.value = await (await getCronDateType()).data
|
||||||
|
|||||||
@ -40,7 +40,7 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog v-model="failReasonDialogShow" :title="t('failReason')" width="60%">
|
<el-dialog v-model="failReasonDialogShow" :title="t('failReason')" width="60%">
|
||||||
<el-scrollbar class="h-[60vh] w-full whitespace-pre p-[20px]">
|
<el-scrollbar class="h-[60vh] w-full whitespace-pre-wrap p-[20px]">
|
||||||
{{ failReason }}
|
{{ failReason }}
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<upload-attachment type="image" ref="imageRef" :limit="10" @confirm="imageSelect" />
|
<upload-attachment type="image" ref="imageRef" limit="" @confirm="imageSelect" />
|
||||||
<upload-attachment type="video" ref="videoRef" @confirm="videoSelect" />
|
<upload-attachment type="video" ref="videoRef" @confirm="videoSelect" />
|
||||||
<vue-ueditor-wrap v-model="content" :config="editorConfig" :editorDependencies="['ueditor.config.js','ueditor.all.js']" ref="editorRef"></vue-ueditor-wrap>
|
<vue-ueditor-wrap v-model="content" :config="editorConfig" :editorDependencies="['ueditor.config.js','ueditor.all.js']" ref="editorRef"></vue-ueditor-wrap>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog v-model="status" :title="t('exportTip')" width="300px" :close-on-click-modal="false" :close-on-press-escape="false" :show-close="false">
|
<el-dialog v-model="status" :title="t('exportTip')" width="300px" :close-on-click-modal="true" :close-on-press-escape="false" :show-close="false">
|
||||||
<span>{{ t('exportPlaceholder') }}</span>
|
<span>{{ t('exportPlaceholder') }}</span>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
@ -52,23 +52,25 @@ const router = useRouter()
|
|||||||
* 导出报表并跳转到下载页
|
* 导出报表并跳转到下载页
|
||||||
*/
|
*/
|
||||||
const detectionExportFn = () => {
|
const detectionExportFn = () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
const url = router.resolve({
|
const url = router.resolve({
|
||||||
path: '/site/setting/export'
|
path: '/site/setting/export'
|
||||||
})
|
})
|
||||||
exportDataCheck(prop.type, { page: 1, limit: 1, ...prop.searchParam }).then((res: any) => {
|
exportDataCheck(prop.type, { page: 1, limit: 1, ...prop.searchParam }).then((res: any) => {
|
||||||
if (res.data) {
|
if (res.data) {
|
||||||
exportData(prop.type, prop.searchParam).then(() => {
|
exportData(prop.type, prop.searchParam).then(() => {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
emit('close', false)
|
emit('close', false)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.open(url.href)
|
window.open(url.href)
|
||||||
}, 100)
|
}, 100)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
emit('close', false)
|
loading.value = false
|
||||||
ElMessage.error(res.msg)
|
ElMessage.error(res.msg)
|
||||||
}
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
loading.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 关闭弹框
|
// 关闭弹框
|
||||||
|
|||||||
@ -113,7 +113,7 @@
|
|||||||
<div class="attachment-item mr-[10px] w-[120px]" v-for="(item, index) in attachment.data" :key="index">
|
<div class="attachment-item mr-[10px] w-[120px]" v-for="(item, index) in attachment.data" :key="index">
|
||||||
<div class="attachment-wrap w-full rounded cursor-pointer overflow-hidden relative flex items-center justify-center h-[120px]">
|
<div class="attachment-wrap w-full rounded cursor-pointer overflow-hidden relative flex items-center justify-center h-[120px]">
|
||||||
<el-image :src="img(item.url)" fit="contain" v-if="type == 'image'" :preview-src-list="item.image_list"/>
|
<el-image :src="img(item.url)" fit="contain" v-if="type == 'image'" :preview-src-list="item.image_list"/>
|
||||||
<video :src="img(item.url)" v-else-if="type == 'video'"></video>
|
<video :src="img(item.url)" v-else-if="type == 'video'" @click="previewVideo(index)"></video>
|
||||||
<icon :name="item.url" size="24px" v-else-if="type == 'icon'"></icon>
|
<icon :name="item.url" size="24px" v-else-if="type == 'icon'"></icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
@ -197,7 +197,7 @@ import {
|
|||||||
getIconList
|
getIconList
|
||||||
} from '@/app/api/sys'
|
} from '@/app/api/sys'
|
||||||
import { debounce, img, getToken } from '@/utils/common'
|
import { debounce, img, getToken } from '@/utils/common'
|
||||||
import { ElMessage, UploadFile, UploadFiles, ElMessageBox } from 'element-plus'
|
import { ElMessage, UploadFile, UploadFiles, ElMessageBox, MessageParams } from 'element-plus'
|
||||||
import storage from '@/utils/storage'
|
import storage from '@/utils/storage'
|
||||||
|
|
||||||
const attachmentCategoryName = ref('')
|
const attachmentCategoryName = ref('')
|
||||||
@ -382,12 +382,24 @@ const upload = computed(() => {
|
|||||||
uploadRef.value?.handleRemove(uploadFile)
|
uploadRef.value?.handleRemove(uploadFile)
|
||||||
} else {
|
} else {
|
||||||
uploadFile.status = 'fail'
|
uploadFile.status = 'fail'
|
||||||
ElMessage({ message: response.msg, type: 'error' })
|
showElMessage({ message: response.msg, type: 'error' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const messageCache = new Map()
|
||||||
|
|
||||||
|
const showElMessage = (options: MessageParams) => {
|
||||||
|
const cacheKey = options.message
|
||||||
|
const cachedMessage = messageCache.get(cacheKey)
|
||||||
|
|
||||||
|
if (!cachedMessage || Date.now() - cachedMessage.timestamp > 5000) { // 5秒内重复内容不再弹出,可自定义过期时间
|
||||||
|
messageCache.set(cacheKey, { timestamp: Date.now() })
|
||||||
|
ElMessage(options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 全选
|
// 全选
|
||||||
const selectAll = ref(false)
|
const selectAll = ref(false)
|
||||||
watch(selectAll, () => {
|
watch(selectAll, () => {
|
||||||
@ -431,7 +443,7 @@ const selectFile = (data: any) => {
|
|||||||
if (prop.limit == 1 && length == prop.limit) {
|
if (prop.limit == 1 && length == prop.limit) {
|
||||||
delete selectedFile[keys[0]]
|
delete selectedFile[keys[0]]
|
||||||
selectedFileIndex.splice(selectedFileIndex.indexOf(keys[0]),1);
|
selectedFileIndex.splice(selectedFileIndex.indexOf(keys[0]),1);
|
||||||
} else if (length >= prop.limit) {
|
} else if (prop.limit && length >= prop.limit) {
|
||||||
ElMessage.info(t('upload.triggerUpperLimit'))
|
ElMessage.info(t('upload.triggerUpperLimit'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,17 @@
|
|||||||
<el-color-picker v-model="theme" />
|
<el-color-picker v-model="theme" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 布局风格 -->
|
||||||
|
<div class="setting-item mb-[10px]">
|
||||||
|
<div class="title text-base text-tx-secondary">{{ t('layout.layoutStyle') }}</div>
|
||||||
|
<div class="flex mt-[10px] layout-style flex-wrap">
|
||||||
|
<div class="relative w-[125px] h-[100px] border mr-[10px] mb-[10px] hover:border-primary"
|
||||||
|
:class="{ 'border-primary': currLayout == item.key }" v-for="(item, index) in layouts"
|
||||||
|
@click="handleSetLayout(item.key)">
|
||||||
|
<img :src="item.image" alt="" class="w-full h-full">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
</div>
|
</div>
|
||||||
@ -27,8 +38,15 @@
|
|||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import useSystemStore from '@/stores/modules/system'
|
import useSystemStore from '@/stores/modules/system'
|
||||||
import { useDark, useToggle } from '@vueuse/core'
|
import { useDark, useToggle } from '@vueuse/core'
|
||||||
import { setThemeColor } from '@/utils/common'
|
import { setThemeColor, img } from '@/utils/common'
|
||||||
import { t } from '@/lang'
|
import { t } from '@/lang'
|
||||||
|
import Storage from '@/utils/storage'
|
||||||
|
|
||||||
|
const layouts = ref([
|
||||||
|
{ key: 'admin', image: img('static/resource/images/system/layout_bussiness.png') },
|
||||||
|
{ key: 'admin_simplicity', image: img('static/resource/images/system/layout_darkside.png') }
|
||||||
|
])
|
||||||
|
const currLayout = ref(Storage.get('admin_layout') || 'admin')
|
||||||
|
|
||||||
const drawer = ref(false)
|
const drawer = ref(false)
|
||||||
const systemStore = useSystemStore()
|
const systemStore = useSystemStore()
|
||||||
@ -66,6 +84,11 @@ const theme = computed({
|
|||||||
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const handleSetLayout = (key: string) => {
|
||||||
|
Storage.set({ key: 'admin_layout', data: key })
|
||||||
|
location.reload()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
65
admin/src/layout/admin_simplicity/components/aside/index.vue
Normal file
65
admin/src/layout/admin_simplicity/components/aside/index.vue
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<template>
|
||||||
|
<el-aside class="layout-aside dark w-auto">
|
||||||
|
<side class="hidden-xs-only slide" />
|
||||||
|
</el-aside>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { watch, computed } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import side from './side.vue'
|
||||||
|
import useSystemStore from '@/stores/modules/system'
|
||||||
|
|
||||||
|
const systemStore = useSystemStore()
|
||||||
|
const dark = computed(() => {
|
||||||
|
return systemStore.dark
|
||||||
|
})
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
watch(route, () => {
|
||||||
|
systemStore.$patch(state => {
|
||||||
|
state.menuDrawer = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.layout-aside {
|
||||||
|
//--side-dark-color: #141414;
|
||||||
|
//background-color: var(--side-dark-color, var(--el-bg-color));
|
||||||
|
|
||||||
|
&.bright {
|
||||||
|
background-color: #F5F7F9;
|
||||||
|
|
||||||
|
li {
|
||||||
|
background-color: #F5F7F9;
|
||||||
|
|
||||||
|
&.is-active:not(.is-opened) {
|
||||||
|
position: relative;
|
||||||
|
color: #333;
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 2px;
|
||||||
|
//background-color: var(--el-menu-active-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide {
|
||||||
|
border-right: 1px solid var(--el-border-color-extra-light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.aside-drawer {
|
||||||
|
.el-drawer__body {
|
||||||
|
padding: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
<template>
|
||||||
|
<template v-if="meta.show">
|
||||||
|
<el-sub-menu v-if="meta.type == 0 && routes.children" :index="String(routes.name)">
|
||||||
|
<template #title>
|
||||||
|
<div class="w-[16px] h-[16px] relative flex items-center" v-if="props.level == 1">
|
||||||
|
<icon v-if="meta.icon" :name="meta.icon" class="absolute !w-auto" />
|
||||||
|
</div>
|
||||||
|
<span class="ml-[10px]">{{ meta.title }}</span>
|
||||||
|
</template>
|
||||||
|
<menu-item v-for="(route, index) in routes.children" :routes="route" :key="index" :level="props.level + 1" />
|
||||||
|
</el-sub-menu>
|
||||||
|
<template v-else>
|
||||||
|
<el-menu-item :index="String(routes.name)" @click="router.push({ name: routes.name })">
|
||||||
|
<div class="w-[16px] h-[16px] relative flex items-center" v-if="props.level == 1">
|
||||||
|
<icon v-if="meta.icon" :name="meta.icon" class="absolute !w-auto" />
|
||||||
|
</div>
|
||||||
|
<template #title>
|
||||||
|
<span class="ml-[10px]">{{ meta.title }}</span>
|
||||||
|
</template>
|
||||||
|
</el-menu-item>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { ref, computed, watch } from 'vue'
|
||||||
|
import { img } from '@/utils/common'
|
||||||
|
import menuItem from './menu-item.vue'
|
||||||
|
import useSystemStore from '@/stores/modules/system'
|
||||||
|
import useUserStore from '@/stores/modules/user'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const routers = useUserStore().routers
|
||||||
|
const props = defineProps({
|
||||||
|
routes: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
level: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const systemStore = useSystemStore()
|
||||||
|
const meta = computed(() => props.routes.meta)
|
||||||
|
|
||||||
|
const addons = computed(() => {
|
||||||
|
const addons:Record<string, any> = {}
|
||||||
|
userStore.siteInfo?.apps.forEach((item: any) => { addons[item.key] = item })
|
||||||
|
userStore.siteInfo?.site_addons.forEach((item: any) => { addons[item.key] = item })
|
||||||
|
return addons
|
||||||
|
})
|
||||||
|
|
||||||
|
const systemAddonKeys = computed(() => {
|
||||||
|
return userStore.siteInfo?.site_addons.map((item: any) => item.key)
|
||||||
|
})
|
||||||
|
|
||||||
|
const addonRouters: Record<string, any> = {}
|
||||||
|
routers.forEach(item => {
|
||||||
|
item.original_name = item.name
|
||||||
|
if (item.meta.addon) {
|
||||||
|
addonRouters[item.meta.addon] = item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const addonsMenus = ref(null)
|
||||||
|
|
||||||
|
watch(route, () => {
|
||||||
|
if (props.routes.name != 'addon_list') return
|
||||||
|
|
||||||
|
if (systemAddonKeys.value.includes(route.meta.addon) && addonRouters[route.meta.addon]) {
|
||||||
|
addonsMenus.value = addonRouters[route.meta.addon]
|
||||||
|
} else {
|
||||||
|
addonsMenus.value = null
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.el-sub-menu{
|
||||||
|
.el-icon{
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
117
admin/src/layout/admin_simplicity/components/aside/side.vue
Normal file
117
admin/src/layout/admin_simplicity/components/aside/side.vue
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<template>
|
||||||
|
<el-container class="h-screen flex flex-col">
|
||||||
|
<el-main class="menu-wrap">
|
||||||
|
<el-header class="logo-wrap flex items-center justify-center h-[64px] w-[var(--aside-width)]">
|
||||||
|
<div class="flex justify-center items-center h-[64px] w-full px-[10px]" v-if="Object.keys(website).length">
|
||||||
|
<el-image :src="img(website.icon)" class="w-[44px] h-[44px] rounded-[50%]" @error="website.icon = img('static/resource/images/niucloud_icon.jpg')"></el-image>
|
||||||
|
<div class="flex-1 w-0 overflow-text truncate ml-[10px] text-white" v-if="!systemStore.menuIsCollapse">
|
||||||
|
<el-tooltip
|
||||||
|
effect="dark"
|
||||||
|
:content="website.site_name"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
{{ website.site_name }}
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-header>
|
||||||
|
<el-scrollbar class="menu-scrollbar flex-1 h-0">
|
||||||
|
<el-menu :default-active="route.name" :router="true" :unique-opened="false" :collapse="systemStore.menuIsCollapse" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b">
|
||||||
|
<menu-item v-for="(route, index) in menuData" :routes="route" :key="index" />
|
||||||
|
</el-menu>
|
||||||
|
<div class="h-[48px]"></div>
|
||||||
|
</el-scrollbar>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import useSystemStore from '@/stores/modules/system'
|
||||||
|
import useUserStore from '@/stores/modules/user'
|
||||||
|
import menuItem from './menu-item.vue'
|
||||||
|
import { img, isUrl } from '@/utils/common'
|
||||||
|
import { findFirstValidRoute } from '@/router/routers'
|
||||||
|
|
||||||
|
const systemStore = useSystemStore()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const route = useRoute()
|
||||||
|
const siteInfo = userStore.siteInfo
|
||||||
|
const routers = userStore.routers
|
||||||
|
const addonIndexRoute = userStore.addonIndexRoute
|
||||||
|
const menuData = ref<Record<string, any>[]>([])
|
||||||
|
const addonRouters: Record<string, any> = {}
|
||||||
|
const website = computed(() => {
|
||||||
|
return systemStore.website
|
||||||
|
})
|
||||||
|
|
||||||
|
routers.forEach(item => {
|
||||||
|
item.original_name = item.name
|
||||||
|
if (item.meta.addon == '') {
|
||||||
|
if (item.children && item.children.length) {
|
||||||
|
item.name = findFirstValidRoute(item.children)
|
||||||
|
}
|
||||||
|
menuData.value.push(item)
|
||||||
|
} else if (item.meta.addon != '' && siteInfo?.apps.length == 1 && siteInfo?.apps[0].key == item.meta.addon) {
|
||||||
|
if (item.children) {
|
||||||
|
item.children.forEach((citem: Record<string, any>) => {
|
||||||
|
citem.original_name = citem.name
|
||||||
|
if (citem.children && citem.children.length) {
|
||||||
|
citem.name = findFirstValidRoute(citem.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
menuData.value.unshift(...item.children)
|
||||||
|
} else {
|
||||||
|
menuData.value.unshift(item)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addonRouters[item.meta.addon] = item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 多应用时将应用插入菜单
|
||||||
|
if (siteInfo?.apps.length > 1) {
|
||||||
|
const routers:Record<string, any>[] = []
|
||||||
|
siteInfo?.apps.forEach((item: Record<string, any>) => {
|
||||||
|
if (addonRouters[item.key]) {
|
||||||
|
addonRouters[item.key].name = addonIndexRoute[item.key]
|
||||||
|
routers.push(addonRouters[item.key])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
menuData.value.unshift(...routers)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.logo-wrap {
|
||||||
|
background: #545c64;
|
||||||
|
transition: transform getCssVar('transition-duration');
|
||||||
|
}
|
||||||
|
:root{
|
||||||
|
--aside-width: 200px;
|
||||||
|
}
|
||||||
|
.menu-wrap {
|
||||||
|
padding: 0!important;
|
||||||
|
background: #545c64;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.el-menu {
|
||||||
|
border-right: 0!important;
|
||||||
|
|
||||||
|
&:not(.el-menu--collapse) {
|
||||||
|
width: var(--aside-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-menu-item, .el-sub-menu__title {
|
||||||
|
--el-menu-item-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-sub-menu .el-menu-item {
|
||||||
|
--el-menu-sub-item-height: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
140
admin/src/layout/admin_simplicity/components/header/index.vue
Normal file
140
admin/src/layout/admin_simplicity/components/header/index.vue
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
<template>
|
||||||
|
<el-container class="h-[64px] layout-admin flex items-center justify-between px-[15px]" >
|
||||||
|
<!-- :class="['h-full px-[10px]',{'layout-header border-b border-color': !dark}]" -->
|
||||||
|
<div class="left-panel flex items-center text-[14px] leading-[1]">
|
||||||
|
<div class="navbar-item flex items-center h-full cursor-pointer" @click="toggleMenuCollapse">
|
||||||
|
<icon name="element Expand" v-if="systemStore.menuIsCollapse" />
|
||||||
|
<icon name="element Fold" v-else />
|
||||||
|
</div>
|
||||||
|
<!-- 刷新当前页 -->
|
||||||
|
<div class="navbar-item flex items-center h-full cursor-pointer" @click="refreshRouter">
|
||||||
|
<icon name="element Refresh" />
|
||||||
|
</div>
|
||||||
|
<!-- 面包屑导航 -->
|
||||||
|
<div class="flex items-center h-full pl-[10px] hidden-xs-only">
|
||||||
|
<el-breadcrumb separator="/">
|
||||||
|
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index">{{route.meta.title }}</el-breadcrumb-item>
|
||||||
|
</el-breadcrumb>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="right-panel h-full flex items-center justify-end">
|
||||||
|
<div class="navbar-item flex items-center h-full cursor-pointer">
|
||||||
|
<layout-setting />
|
||||||
|
</div>
|
||||||
|
<!-- 用户信息 -->
|
||||||
|
<div class="navbar-item flex items-center h-full cursor-pointer">
|
||||||
|
<user-info />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" v-model="comparisonToken">
|
||||||
|
<input type="hidden" v-model="comparisonSiteId">
|
||||||
|
|
||||||
|
<el-dialog v-model="detectionLoginDialog" :title="t('layout.detectionLoginTip')" width="30%" :close-on-click-modal="false" :close-on-press-escape="false" :show-close="false">
|
||||||
|
<span>{{ t('layout.detectionLoginContent') }}</span>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="detectionLoginFn">{{ t('layout.detectionLoginOperation') }}</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog v-model="showDialog" :title="t('indexTemplate')" width="550px" :destroy-on-close="true" >
|
||||||
|
<div class="flex flex-wrap">
|
||||||
|
<div v-for="(items, index) in indexList" :key="index" v-if="index_path == ''">
|
||||||
|
<div @click="index_path = items.view_path" class="index-item py-[5px] px-[10px] mr-[10px] rounded-[3px] cursor-pointer" :class="items.is_use == 1 ? 'bg-primary text-[#fff]' : '' ">
|
||||||
|
<span >{{ items.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-for="(itemTo, indexTo) in indexList" :key="indexTo" v-else>
|
||||||
|
<div @click="index_path = itemTo.view_path" class="index-item py-[5px] px-[10px] mr-[10px] rounded-[3px] cursor-pointer" :class="index_path == itemTo.view_path ? 'bg-primary text-[#fff]' : '' ">
|
||||||
|
<span >{{ itemTo.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitIndex">{{ t('confirm') }}</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</el-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import useUserStore from '@/stores/modules/user'
|
||||||
|
import useAppStore from '@/stores/modules/app'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import { t } from '@/lang'
|
||||||
|
import storage from '@/utils/storage'
|
||||||
|
import userInfo from './user-info.vue'
|
||||||
|
import layoutSetting from './layout-setting.vue'
|
||||||
|
import useSystemStore from "@/stores/modules/system";
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const appStore = useAppStore()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const systemStore = useSystemStore()
|
||||||
|
|
||||||
|
// 检测登录 start
|
||||||
|
const detectionLoginDialog = ref(false)
|
||||||
|
const comparisonToken = ref('')
|
||||||
|
const comparisonSiteId = ref('')
|
||||||
|
if (storage.get('comparisonTokenStorage')) {
|
||||||
|
comparisonToken.value = storage.get('comparisonTokenStorage')
|
||||||
|
}
|
||||||
|
if (storage.get('comparisonSiteIdStorage')) {
|
||||||
|
comparisonSiteId.value = storage.get('comparisonSiteIdStorage')
|
||||||
|
}
|
||||||
|
// 监听标签页面切换
|
||||||
|
document.addEventListener('visibilitychange', e => {
|
||||||
|
if (document.visibilityState === 'visible' && (comparisonSiteId.value != storage.get('siteId') || comparisonToken.value != storage.get('token'))) {
|
||||||
|
detectionLoginDialog.value = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
systemStore.toggleMenuCollapse(storage.get('menuiscollapse') || false)
|
||||||
|
|
||||||
|
const detectionLoginFn = () => {
|
||||||
|
detectionLoginDialog.value = false
|
||||||
|
location.reload()
|
||||||
|
}
|
||||||
|
// 检测登录 end
|
||||||
|
|
||||||
|
// 刷新路由
|
||||||
|
const refreshRouter = () => {
|
||||||
|
if (!appStore.routeRefreshTag) return
|
||||||
|
appStore.refreshRouterView()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 面包屑导航
|
||||||
|
const breadcrumb = computed(() => {
|
||||||
|
const matched = route.matched.filter(item => { return item.meta.title })
|
||||||
|
if (matched[0] && matched[0].path == '/') matched.splice(0, 1)
|
||||||
|
return matched
|
||||||
|
})
|
||||||
|
storage.set({ key: 'currHeadMenuName', data: "" })
|
||||||
|
|
||||||
|
const toggleMenuCollapse = () => {
|
||||||
|
systemStore.toggleMenuCollapse(!systemStore.menuIsCollapse)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.layout-header{
|
||||||
|
position: relative;
|
||||||
|
z-index: 5;
|
||||||
|
border-bottom: 1px solid #e8e9eb;
|
||||||
|
}
|
||||||
|
.navbar-item {
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
.index-item {
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: var(--el-color-primary);
|
||||||
|
&:hover {
|
||||||
|
color: #fff;
|
||||||
|
background-color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex">
|
||||||
|
<icon name="element Setting" @click="drawer = true" />
|
||||||
|
|
||||||
|
<el-drawer v-model="drawer" :title="t('layout.layoutSetting')" size="300px">
|
||||||
|
<el-scrollbar>
|
||||||
|
<!-- 黑暗模式 -->
|
||||||
|
<div class="setting-item flex items-center justify-between mb-[10px]">
|
||||||
|
<div class="title text-base text-tx-secondary">{{ t('layout.darkMode') }}</div>
|
||||||
|
<div>
|
||||||
|
<el-switch v-model="dark" :active-value="true" :inactive-value="false" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 主题颜色 -->
|
||||||
|
<div class="setting-item flex items-center justify-between mb-[10px]">
|
||||||
|
<div class="title text-base text-tx-secondary">{{ t('layout.themeColor') }}</div>
|
||||||
|
<div>
|
||||||
|
<el-color-picker v-model="theme" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 布局风格 -->
|
||||||
|
<div class="setting-item mb-[10px]">
|
||||||
|
<div class="title text-base text-tx-secondary">{{ t('layout.layoutStyle') }}</div>
|
||||||
|
<div class="flex mt-[10px] layout-style flex-wrap">
|
||||||
|
<div class="relative w-[125px] h-[100px] border mr-[10px] mb-[10px] hover:border-primary"
|
||||||
|
:class="{ 'border-primary': currLayout == item.key }" v-for="(item, index) in layouts"
|
||||||
|
@click="handleSetLayout(item.key)">
|
||||||
|
<img :src="item.image" alt="" class="w-full h-full">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
</el-drawer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import useSystemStore from '@/stores/modules/system'
|
||||||
|
import { useDark, useToggle } from '@vueuse/core'
|
||||||
|
import { setThemeColor, img } from '@/utils/common'
|
||||||
|
import { t } from '@/lang'
|
||||||
|
import Storage from '@/utils/storage'
|
||||||
|
|
||||||
|
const layouts = ref([
|
||||||
|
{ key: 'admin', image: img('static/resource/images/system/layout_bussiness.png') },
|
||||||
|
{ key: 'admin_simplicity', image: img('static/resource/images/system/layout_darkside.png') }
|
||||||
|
])
|
||||||
|
const currLayout = ref(Storage.get('admin_layout') || 'admin')
|
||||||
|
|
||||||
|
const drawer = ref(false)
|
||||||
|
const systemStore = useSystemStore()
|
||||||
|
|
||||||
|
const isDark = useDark()
|
||||||
|
const toggleDark = useToggle(isDark)
|
||||||
|
|
||||||
|
const dark = computed({
|
||||||
|
get() {
|
||||||
|
return systemStore.dark
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
systemStore.setTheme('dark', val)
|
||||||
|
toggleDark(val)
|
||||||
|
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const sidebar = computed({
|
||||||
|
get() {
|
||||||
|
return systemStore.sidebar
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
systemStore.setTheme('sidebar', val)
|
||||||
|
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const theme = computed({
|
||||||
|
get() {
|
||||||
|
return systemStore.theme
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
systemStore.setTheme('theme', val)
|
||||||
|
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSetLayout = (key: string) => {
|
||||||
|
Storage.set({ key: 'admin_layout', data: key })
|
||||||
|
location.reload()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.el-drawer__header) {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-style {
|
||||||
|
&>div:nth-child(2n+2) {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<el-dropdown @command="switchLang" :tabindex="1">
|
||||||
|
<icon name="iconfont iconfanyi" />
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item command="zh-cn" :disabled="systemStore.lang == 'zh-cn'">简体中文</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="en" :disabled="systemStore.lang == 'en'">English</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import useSystemStore from '@/stores/modules/system'
|
||||||
|
import { language } from '@/lang'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import storage from '@/utils/storage'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const systemStore = useSystemStore()
|
||||||
|
|
||||||
|
const switchLang = (command: string) => {
|
||||||
|
systemStore.$patch((state) => {
|
||||||
|
state.lang = command
|
||||||
|
storage.set({ key: 'lang', data: command })
|
||||||
|
})
|
||||||
|
language.loadLocaleMessages(route.path, systemStore.lang)
|
||||||
|
location.reload()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@ -0,0 +1,147 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-dropdown @command="clickEvent" :tabindex="1">
|
||||||
|
<div class="userinfo flex h-full items-center">
|
||||||
|
<el-avatar v-if="userStore.userInfo.head_img" :size="25" :icon="UserFilled" :src="img(userStore.userInfo.head_img)"/>
|
||||||
|
<img v-else src="@/app/assets/images/member_head.png" class="w-[25px] rounded-full" />
|
||||||
|
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
||||||
|
<icon name="element ArrowDown" class="ml-[5px]" />
|
||||||
|
</div>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item @click="getUserInfoFn">
|
||||||
|
<!-- <router-link to="/user/center"> -->
|
||||||
|
<div class="flex items-center leading-[1] py-[5px]">
|
||||||
|
<span class="iconfont iconshezhi1 ml-[4px] !text-[14px] mr-[10px]"></span>
|
||||||
|
<span class="text-[14px]">账号设置</span>
|
||||||
|
</div>
|
||||||
|
<!-- </router-link> -->
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item>
|
||||||
|
<router-link to="/tools/authorize">
|
||||||
|
<div class="flex items-center leading-[1] py-[5px]">
|
||||||
|
<span class="iconfont iconshouquanxinxi2 ml-[4px] !text-[14px] mr-[10px]"></span>
|
||||||
|
<span class="text-[14px]">授权信息</span>
|
||||||
|
</div>
|
||||||
|
</router-link>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click="changePasswordDialog=true">
|
||||||
|
<div class="flex items-center leading-[1] py-[5px]">
|
||||||
|
<span class="iconfont iconxiugai ml-[4px] !text-[14px] mr-[10px]"></span>
|
||||||
|
<span class="text-[14px]">修改密码</span>
|
||||||
|
</div>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click="logout">
|
||||||
|
<div class="flex items-center leading-[1] py-[5px]">
|
||||||
|
<span class="iconfont icontuichudenglu ml-[4px] !text-[14px] mr-[10px]"></span>
|
||||||
|
<span class="text-[14px]">退出登录</span>
|
||||||
|
</div>
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
<el-dialog v-model="changePasswordDialog" width="450px" title="修改密码">
|
||||||
|
<div>
|
||||||
|
<el-form :model="saveInfo" label-width="90px" ref="formRef" :rules="formRules" class="page-form">
|
||||||
|
<el-form-item :label="t('originalPassword')" prop="original_password">
|
||||||
|
<el-input v-model="saveInfo.original_password" type="password" :placeholder="t('originalPasswordPlaceholder')" clearable class="input-width" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="t('newPassword')" prop="password">
|
||||||
|
<el-input v-model="saveInfo.password" type="password" :placeholder="t('passwordPlaceholder')" clearable class="input-width" />
|
||||||
|
<div class="form-tip">{{t('passwordTip')}}</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="t('passwordCopy')" prop="password_copy">
|
||||||
|
<el-input v-model="saveInfo.password_copy" type="password" :placeholder="t('passwordPlaceholder')" clearable class="input-width" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="changePasswordDialog = false">{{t('cancel')}}</el-button>
|
||||||
|
<el-button type="primary" @click="submitForm(formRef)">{{t('save')}}</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
<user-info-edit ref="userInfoEditRef" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { UserFilled } from '@element-plus/icons-vue'
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
||||||
|
import useUserStore from '@/stores/modules/user'
|
||||||
|
import { setUserInfo } from '@/app/api/personal'
|
||||||
|
import { t } from '@/lang'
|
||||||
|
import { img } from '@/utils/common'
|
||||||
|
import userInfoEdit from '@/app/components/user-info-edit/index.vue'
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
const clickEvent = (command: string) => {
|
||||||
|
switch (command) {
|
||||||
|
case 'logout':
|
||||||
|
userStore.logout()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const logout = () => {
|
||||||
|
userStore.logout();
|
||||||
|
}
|
||||||
|
const userInfoEditRef = ref(null)
|
||||||
|
const getUserInfoFn = ()=>{
|
||||||
|
userInfoEditRef.value?.open()
|
||||||
|
}
|
||||||
|
// 修改密码 --- start
|
||||||
|
const changePasswordDialog = ref(false)
|
||||||
|
const formRef = ref<FormInstance>();
|
||||||
|
// 提交信息
|
||||||
|
const saveInfo = reactive({
|
||||||
|
original_password: '',
|
||||||
|
password: '',
|
||||||
|
password_copy: ''
|
||||||
|
});
|
||||||
|
// 表单验证规则
|
||||||
|
const formRules = reactive<FormRules>({
|
||||||
|
original_password: [
|
||||||
|
{ required: true, message: t("originalPasswordPlaceholder"), trigger: "blur" },
|
||||||
|
],
|
||||||
|
password: [
|
||||||
|
{ required: true, message: t("passwordPlaceholder"), trigger: "blur" },
|
||||||
|
],
|
||||||
|
password_copy: [
|
||||||
|
{ required: true, message: t("passwordPlaceholder"), trigger: "blur" },
|
||||||
|
]
|
||||||
|
});
|
||||||
|
const submitForm = (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return
|
||||||
|
formEl.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
let msg = "";
|
||||||
|
if (saveInfo.password && !saveInfo.original_password) msg = t('originalPasswordHint');
|
||||||
|
if (saveInfo.password && saveInfo.original_password && !saveInfo.password_copy) msg = t('newPasswordHint');
|
||||||
|
if (saveInfo.password && saveInfo.original_password && saveInfo.password_copy && saveInfo.password != saveInfo.password_copy) msg = t('doubleCipherHint');
|
||||||
|
if (msg) {
|
||||||
|
ElNotification({
|
||||||
|
type: 'error',
|
||||||
|
message: msg,
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setUserInfo(saveInfo).then((res: any) => {
|
||||||
|
changePasswordDialog.value = false;
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.el-popper .el-dropdown-menu{
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
136
admin/src/layout/admin_simplicity/components/tabs.vue
Normal file
136
admin/src/layout/admin_simplicity/components/tabs.vue
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
<template>
|
||||||
|
<div class="tab-wrap w-full px-[16px]">
|
||||||
|
<el-tabs :closable="tabbarStore.tabLength > 1" :model-value="route.path" @tab-click="tabClick" @tab-remove="removeTab">
|
||||||
|
<el-tab-pane v-for="(tab, key, index) in tabbarStore.tabs" :name="tab.path" :key="index">
|
||||||
|
<template #label>
|
||||||
|
<el-dropdown trigger="contextmenu" placement="bottom-start">
|
||||||
|
<span :class="{ 'text-primary': route.path == tab.path }" class="tab-name">{{ tab.title }}</span>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item icon="Back" :disabled="index == 0" @click="closeLeft(tab.path)">{{t('tabs.closeLeft') }}</el-dropdown-item>
|
||||||
|
<el-dropdown-item icon="Right" :disabled="index == (tabbarStore.tabLength - 1)" @click="closeRight(tab.path)">{{t('tabs.closeRight') }}</el-dropdown-item>
|
||||||
|
<el-dropdown-item icon="Close" :disabled="tabbarStore.tabLength == 1" @click="closeOther(tab.path)">{{t('tabs.closeOther') }}</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</template>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { watch, onMounted } from 'vue'
|
||||||
|
import useTabbarStore from '@/stores/modules/tabbar'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import { t } from '@/lang'
|
||||||
|
|
||||||
|
const tabbarStore = useTabbarStore()
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
tabbarStore.addTab(route)
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(route, (nval: any) => {
|
||||||
|
tabbarStore.addTab(nval)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加tab
|
||||||
|
* @param content
|
||||||
|
*/
|
||||||
|
const tabClick = (content: any) => {
|
||||||
|
const tabRoute = tabbarStore.tabs[content.props.name]
|
||||||
|
router.push({ path: tabRoute.path, query: tabRoute.query })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除tab
|
||||||
|
* @param content
|
||||||
|
*/
|
||||||
|
const removeTab = (content: any) => {
|
||||||
|
if (route.path == content) {
|
||||||
|
const tabs = Object.keys(tabbarStore.tabs)
|
||||||
|
router.push({ path: tabs[tabs.indexOf(content) - 1] })
|
||||||
|
}
|
||||||
|
tabbarStore.removeTab(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭左侧
|
||||||
|
* @param path
|
||||||
|
*/
|
||||||
|
const closeLeft = (path: string) => {
|
||||||
|
const tabs = Object.keys(tabbarStore.tabs)
|
||||||
|
for (let i = tabs.indexOf(path) - 1; i >= 0; i--) {
|
||||||
|
delete tabbarStore.tabs[tabs[i]]
|
||||||
|
}
|
||||||
|
router.push({ path })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭右侧
|
||||||
|
* @param path
|
||||||
|
*/
|
||||||
|
const closeRight = (path: string) => {
|
||||||
|
const tabs = Object.keys(tabbarStore.tabs)
|
||||||
|
for (let i = tabs.indexOf(path) + 1; i < tabs.length; i++) {
|
||||||
|
delete tabbarStore.tabs[tabs[i]]
|
||||||
|
}
|
||||||
|
router.push({ path })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭其他
|
||||||
|
* @param path
|
||||||
|
*/
|
||||||
|
const closeOther = (path: string) => {
|
||||||
|
const tabs = Object.keys(tabbarStore.tabs)
|
||||||
|
tabs.forEach((key: string) => { key != path && delete tabbarStore.tabs[key] })
|
||||||
|
router.push({ path })
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.el-tabs) {
|
||||||
|
.el-tabs--border-card {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__header {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__nav-wrap {
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__content {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__item {
|
||||||
|
display: inline-flex !important;
|
||||||
|
padding: 0 20px !important;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.tab-name:focus {
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__active-bar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__item.is-active {
|
||||||
|
background-color: var(--el-color-primary-light-9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
41
admin/src/layout/admin_simplicity/index.vue
Normal file
41
admin/src/layout/admin_simplicity/index.vue
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex w-full h-screen">
|
||||||
|
<!-- 左侧边栏 -->
|
||||||
|
<layout-aside></layout-aside>
|
||||||
|
<!-- 左侧边栏 end -->
|
||||||
|
|
||||||
|
<el-container>
|
||||||
|
<!-- 顶部 -->
|
||||||
|
<el-header>
|
||||||
|
<layout-header></layout-header>
|
||||||
|
</el-header>
|
||||||
|
<!-- 顶部 end -->
|
||||||
|
|
||||||
|
<!-- 主体 -->
|
||||||
|
<el-main class="h-full p-0 bg-page">
|
||||||
|
<el-scrollbar>
|
||||||
|
<div class="p-[15px]">
|
||||||
|
<router-view v-slot="{ Component, route }" v-if="appStore.routeRefreshTag">
|
||||||
|
<keep-alive :include="tabbarStore.tabNames">
|
||||||
|
<component :is="Component" :key="route.fullPath" />
|
||||||
|
</keep-alive>
|
||||||
|
</router-view>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
</el-main>
|
||||||
|
<!-- 主体 end -->
|
||||||
|
</el-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import layoutHeader from './components/header/index.vue'
|
||||||
|
import layoutAside from './components/aside/index.vue'
|
||||||
|
import useAppStore from '@/stores/modules/app'
|
||||||
|
import useTabbarStore from '@/stores/modules/tabbar'
|
||||||
|
|
||||||
|
const appStore = useAppStore()
|
||||||
|
const tabbarStore = useTabbarStore()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@ -7,6 +7,7 @@ import { ref, markRaw, defineAsyncComponent, provide } from 'vue'
|
|||||||
import { getAppType } from '@/utils/common'
|
import { getAppType } from '@/utils/common'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import useUserStore from '@/stores/modules/user'
|
||||||
import useSystemStore from '@/stores/modules/system'
|
import useSystemStore from '@/stores/modules/system'
|
||||||
|
import Storage from '@/utils/storage'
|
||||||
|
|
||||||
const sysLayout = import.meta.glob('./*/index.vue')
|
const sysLayout = import.meta.glob('./*/index.vue')
|
||||||
const addonLayout = import.meta.glob('@/addon/**/layout/index.vue')
|
const addonLayout = import.meta.glob('@/addon/**/layout/index.vue')
|
||||||
@ -15,7 +16,7 @@ const modules = Object.assign(sysLayout, addonLayout)
|
|||||||
let siteLayout = 'default'
|
let siteLayout = 'default'
|
||||||
switch (getAppType()) {
|
switch (getAppType()) {
|
||||||
case 'admin':
|
case 'admin':
|
||||||
siteLayout = 'admin'
|
siteLayout = Storage.get('admin_layout') || 'admin'
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
const siteInfo = useUserStore().siteInfo
|
const siteInfo = useUserStore().siteInfo
|
||||||
|
|||||||
@ -90,7 +90,7 @@ html, body {
|
|||||||
|
|
||||||
.fixed-footer {
|
.fixed-footer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1000;
|
z-index: 4;
|
||||||
right: 15px;
|
right: 15px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 15px;
|
left: 15px;
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
/* addon-iconfont.css */
|
/* addon iconfont */
|
||||||
|
|||||||
0
niucloud/addon/.gitignore
vendored
0
niucloud/addon/.gitignore
vendored
@ -106,7 +106,7 @@ class User extends BaseAdminController
|
|||||||
*/
|
*/
|
||||||
public function del($uid)
|
public function del($uid)
|
||||||
{
|
{
|
||||||
(new UserService())->del($uid);
|
(new SiteUserService())->del($uid);
|
||||||
return success('DELETE_SUCCESS');
|
return success('DELETE_SUCCESS');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,7 +29,7 @@ class Schedule extends BaseAdminController
|
|||||||
{
|
{
|
||||||
$data = $this->request->params([
|
$data = $this->request->params([
|
||||||
['key', ''],
|
['key', ''],
|
||||||
['status', ''],
|
['status', 'all'],
|
||||||
]);
|
]);
|
||||||
return success(data: (new ScheduleService())->getPage($data));
|
return success(data: (new ScheduleService())->getPage($data));
|
||||||
|
|
||||||
|
|||||||
@ -86,6 +86,21 @@ class User extends BaseAdminController
|
|||||||
return success();
|
return success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑用户
|
||||||
|
* @return Response
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function edit($uid) {
|
||||||
|
$data = $this->request->params([
|
||||||
|
['password', ''],
|
||||||
|
['real_name', ''],
|
||||||
|
['head_img', ''],
|
||||||
|
]);
|
||||||
|
(new UserService())->edit($uid, $data);
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除用户
|
* 删除用户
|
||||||
* @param $uid
|
* @param $uid
|
||||||
|
|||||||
@ -67,6 +67,8 @@ Route::group('site', function () {
|
|||||||
Route::put('user/:uid', 'site.User/edit');
|
Route::put('user/:uid', 'site.User/edit');
|
||||||
//站点修改用户属性
|
//站点修改用户属性
|
||||||
Route::put('user/:uid/:field', 'site.User/modify');
|
Route::put('user/:uid/:field', 'site.User/modify');
|
||||||
|
//站点删除用户
|
||||||
|
Route::delete('user/:uid', 'site.User/del');
|
||||||
/***************************************************** 操作日志 **************************************************/
|
/***************************************************** 操作日志 **************************************************/
|
||||||
//操作日志列表
|
//操作日志列表
|
||||||
Route::get('log', 'site.UserLog/lists');
|
Route::get('log', 'site.UserLog/lists');
|
||||||
|
|||||||
@ -34,6 +34,8 @@ Route::group('user', function () {
|
|||||||
Route::get('isexist', 'user.User/checkUserIsExist');
|
Route::get('isexist', 'user.User/checkUserIsExist');
|
||||||
//添加用户
|
//添加用户
|
||||||
Route::post('user', 'user.User/add');
|
Route::post('user', 'user.User/add');
|
||||||
|
// 编辑用户
|
||||||
|
Route::put('user/:uid', 'user.User/edit');
|
||||||
// 获取用户站点创建限制
|
// 获取用户站点创建限制
|
||||||
Route::get('user/create_site_limit/:uid', 'user.User/getUserCreateSiteLimit');
|
Route::get('user/create_site_limit/:uid', 'user.User/getUserCreateSiteLimit');
|
||||||
// 获取用户站点创建限制
|
// 获取用户站点创建限制
|
||||||
|
|||||||
@ -43,18 +43,18 @@ class ApiCheckToken
|
|||||||
try {
|
try {
|
||||||
$token = $request->apiToken();
|
$token = $request->apiToken();
|
||||||
$token_info = ( new LoginService() )->parseToken($token);
|
$token_info = ( new LoginService() )->parseToken($token);
|
||||||
|
if (!empty($token_info)) {
|
||||||
|
$request->memberId($token_info[ 'member_id' ]);
|
||||||
|
}
|
||||||
|
//校验会员和站点
|
||||||
|
( new AuthService() )->checkSiteAuth($request);
|
||||||
|
// 校验渠道
|
||||||
|
( new AuthService() )->checkChannel($request);
|
||||||
} catch (AuthException $e) {
|
} catch (AuthException $e) {
|
||||||
//是否将登录错误抛出
|
//是否将登录错误抛出
|
||||||
if ($is_throw_exception)
|
if ($is_throw_exception)
|
||||||
return fail($e->getMessage(), [], $e->getCode());
|
return fail($e->getMessage(), [], $e->getCode());
|
||||||
}
|
}
|
||||||
if (!empty($token_info)) {
|
|
||||||
$request->memberId($token_info[ 'member_id' ]);
|
|
||||||
}
|
|
||||||
//校验会员和站点
|
|
||||||
( new AuthService() )->checkSiteAuth($request);
|
|
||||||
// 校验渠道
|
|
||||||
( new AuthService() )->checkChannel($request);
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
niucloud/app/command/Resetpassword.php
Normal file
29
niucloud/app/command/Resetpassword.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\command;
|
||||||
|
|
||||||
|
use app\service\admin\auth\LoginService;
|
||||||
|
use app\service\admin\install\InstallSystemService;
|
||||||
|
use app\service\core\menu\CoreMenuService;
|
||||||
|
use think\console\Command;
|
||||||
|
use think\console\Input;
|
||||||
|
use think\console\input\Option;
|
||||||
|
use think\console\Output;
|
||||||
|
|
||||||
|
class Resetpassword extends Command
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
// 指令配置
|
||||||
|
$this->setName('reset')
|
||||||
|
->setDescription('the reset administrator password command');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(Input $input, Output $output)
|
||||||
|
{
|
||||||
|
LoginService::resetAdministratorPassword();
|
||||||
|
// 指令输出
|
||||||
|
$output->writeln('password reset success');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -69,10 +69,10 @@ function get_lang($str)
|
|||||||
function list_to_tree($list, $pk = 'id', $pid = 'pid', $child = 'child', $root = 0)
|
function list_to_tree($list, $pk = 'id', $pid = 'pid', $child = 'child', $root = 0)
|
||||||
{
|
{
|
||||||
// 创建Tree
|
// 创建Tree
|
||||||
$tree = array ();
|
$tree = array();
|
||||||
if (is_array($list)) {
|
if (is_array($list)) {
|
||||||
// 创建基于主键的数组引用
|
// 创建基于主键的数组引用
|
||||||
$refer = array ();
|
$refer = array();
|
||||||
foreach ($list as $key => $data) {
|
foreach ($list as $key => $data) {
|
||||||
$refer[ $data[ $pk ] ] =& $list[ $key ];
|
$refer[ $data[ $pk ] ] =& $list[ $key ];
|
||||||
}
|
}
|
||||||
@ -132,7 +132,7 @@ function array_keys_search($array, $keys, $index = '', $is_sort = true)
|
|||||||
return [];
|
return [];
|
||||||
if (!empty($index) && count($array) != count($array, COUNT_RECURSIVE))
|
if (!empty($index) && count($array) != count($array, COUNT_RECURSIVE))
|
||||||
$array = array_column($array, null, $index);
|
$array = array_column($array, null, $index);
|
||||||
$list = array ();
|
$list = array();
|
||||||
|
|
||||||
foreach ($keys as $key) {
|
foreach ($keys as $key) {
|
||||||
if (isset($array[ $key ])) {
|
if (isset($array[ $key ])) {
|
||||||
@ -502,7 +502,7 @@ function array_merge2(array $array1, array $array2)
|
|||||||
function get_files_by_dir($dir)
|
function get_files_by_dir($dir)
|
||||||
{
|
{
|
||||||
$dh = @opendir($dir); //打开目录,返回一个目录流
|
$dh = @opendir($dir); //打开目录,返回一个目录流
|
||||||
$return = array ();
|
$return = array();
|
||||||
while ($file = @readdir($dh)) { //循环读取目录下的文件
|
while ($file = @readdir($dh)) { //循环读取目录下的文件
|
||||||
if ($file != '.' and $file != '..') {
|
if ($file != '.' and $file != '..') {
|
||||||
$path = $dir . DIRECTORY_SEPARATOR . $file; //设置目录,用于含有子目录的情况
|
$path = $dir . DIRECTORY_SEPARATOR . $file; //设置目录,用于含有子目录的情况
|
||||||
@ -947,3 +947,18 @@ function str_sub($str, $length = 10, $is_need_apostrophe = true)
|
|||||||
{
|
{
|
||||||
return mb_substr($str, 0, $length, 'UTF-8') . ( $is_need_apostrophe ? '...' : '' );
|
return mb_substr($str, 0, $length, 'UTF-8') . ( $is_need_apostrophe ? '...' : '' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用正则表达式匹配特殊字符
|
||||||
|
* @param $str
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function is_special_character($str)
|
||||||
|
{
|
||||||
|
$pattern = '/[!@#$%^&*()\[\]{}<>\|?:;"]/';
|
||||||
|
if (preg_match($pattern, $str)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ class CommonDict
|
|||||||
public const UNKNOWN = 0;
|
public const UNKNOWN = 0;
|
||||||
public const MAN = 1;
|
public const MAN = 1;
|
||||||
public const WOMAN = 2;
|
public const WOMAN = 2;
|
||||||
|
public const ENCRYPT_STR = '*****************************';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 性别
|
* 性别
|
||||||
@ -26,4 +26,4 @@ class CommonDict
|
|||||||
self::WOMAN => get_lang('dict_sex.woman'),//女
|
self::WOMAN => get_lang('dict_sex.woman'),//女
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -233,6 +233,20 @@ return [
|
|||||||
'sort' => '100',
|
'sort' => '100',
|
||||||
'status' => '1',
|
'status' => '1',
|
||||||
'is_show' => '1',
|
'is_show' => '1',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'menu_name' => '删除管理员',
|
||||||
|
'menu_key' => 'delete_site_user',
|
||||||
|
'menu_short_name' => '删除管理员',
|
||||||
|
'menu_type' => '2',
|
||||||
|
'icon' => '',
|
||||||
|
'api_url' => 'site/user/<uid>',
|
||||||
|
'router_path' => '',
|
||||||
|
'view_path' => '',
|
||||||
|
'methods' => 'delete',
|
||||||
|
'sort' => '100',
|
||||||
|
'status' => '1',
|
||||||
|
'is_show' => '1',
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
@ -828,7 +842,7 @@ return [
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'menu_name' => '用户',
|
'menu_name' => '用户管理',
|
||||||
'menu_key' => 'site_user_list',
|
'menu_key' => 'site_user_list',
|
||||||
'menu_short_name' => '用户',
|
'menu_short_name' => '用户',
|
||||||
'menu_type' => '1',
|
'menu_type' => '1',
|
||||||
@ -1043,7 +1057,7 @@ return [
|
|||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'menu_name' => '开发',
|
'menu_name' => '开发管理',
|
||||||
'menu_key' => 'app_manage_tool',
|
'menu_key' => 'app_manage_tool',
|
||||||
'menu_short_name' => '开发',
|
'menu_short_name' => '开发',
|
||||||
'menu_type' => '1',
|
'menu_type' => '1',
|
||||||
|
|||||||
@ -1618,6 +1618,20 @@ return [
|
|||||||
'sort' => '100',
|
'sort' => '100',
|
||||||
'status' => '1',
|
'status' => '1',
|
||||||
'is_show' => '1',
|
'is_show' => '1',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'menu_name' => '删除管理员',
|
||||||
|
'menu_key' => 'delete_site_user',
|
||||||
|
'menu_short_name' => '删除管理员',
|
||||||
|
'menu_type' => '2',
|
||||||
|
'icon' => '',
|
||||||
|
'api_url' => 'site/user/<uid>',
|
||||||
|
'router_path' => '',
|
||||||
|
'view_path' => '',
|
||||||
|
'methods' => 'delete',
|
||||||
|
'sort' => '100',
|
||||||
|
'status' => '1',
|
||||||
|
'is_show' => '1',
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
|||||||
@ -57,19 +57,22 @@ class PayDict
|
|||||||
'name' => get_lang('dict_pay.type_wechatpay'),
|
'name' => get_lang('dict_pay.type_wechatpay'),
|
||||||
'key' => self::WECHATPAY,
|
'key' => self::WECHATPAY,
|
||||||
'icon' => self::WECHATPAY_ICON,
|
'icon' => self::WECHATPAY_ICON,
|
||||||
'setting_component' => '/src/app/views/setting/components/pay-wechatpay.vue'
|
'setting_component' => '/src/app/views/setting/components/pay-wechatpay.vue',
|
||||||
|
'encrypt_params' => ['mch_public_cert_path', 'mch_secret_cert', 'mch_secret_key'],
|
||||||
],//微信支付
|
],//微信支付
|
||||||
self::ALIPAY => [
|
self::ALIPAY => [
|
||||||
'name' => get_lang('dict_pay.type_alipay'),
|
'name' => get_lang('dict_pay.type_alipay'),
|
||||||
'key' => self::ALIPAY,
|
'key' => self::ALIPAY,
|
||||||
'icon' => self::ALIPAY_ICON,
|
'icon' => self::ALIPAY_ICON,
|
||||||
'setting_component' => '/src/app/views/setting/components/pay-alipay.vue'
|
'setting_component' => '/src/app/views/setting/components/pay-alipay.vue',
|
||||||
|
'encrypt_params' => ['app_secret_cert', 'app_public_cert_path', 'alipay_public_cert_path', 'alipay_root_cert_path'],
|
||||||
],//支付宝支付
|
],//支付宝支付
|
||||||
self::BALANCEPAY => [
|
self::BALANCEPAY => [
|
||||||
'name' => get_lang('dict_pay.type_balancepay'),
|
'name' => get_lang('dict_pay.type_balancepay'),
|
||||||
'key' => self::BALANCEPAY,
|
'key' => self::BALANCEPAY,
|
||||||
'icon' => self::BALANCEPAY_ICON,
|
'icon' => self::BALANCEPAY_ICON,
|
||||||
'setting_component' => ''
|
'setting_component' => '',
|
||||||
|
'encrypt_params' => ['secret_key'],
|
||||||
],//微信支付
|
],//微信支付
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -47,6 +47,7 @@ class SmsDict
|
|||||||
'app_key' => 'APP_KEY',
|
'app_key' => 'APP_KEY',
|
||||||
'secret_key' => 'SECRET_KEY'
|
'secret_key' => 'SECRET_KEY'
|
||||||
],
|
],
|
||||||
|
'encrypt_params' => ['secret_key'],
|
||||||
'component' => '/src/app/views/setting/components/sms-ali.vue',
|
'component' => '/src/app/views/setting/components/sms-ali.vue',
|
||||||
],
|
],
|
||||||
self::TENCENTSMS => [
|
self::TENCENTSMS => [
|
||||||
@ -58,6 +59,7 @@ class SmsDict
|
|||||||
'secret_id' => 'SECRET_ID',
|
'secret_id' => 'SECRET_ID',
|
||||||
'secret_key' => 'SECRET_KEY'
|
'secret_key' => 'SECRET_KEY'
|
||||||
],
|
],
|
||||||
|
'encrypt_params' => ['secret_key'],
|
||||||
'component' => '/src/app/views/setting/components/sms-tencent.vue',
|
'component' => '/src/app/views/setting/components/sms-tencent.vue',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@ -54,6 +54,7 @@ class StorageDict
|
|||||||
'secret_key' => 'SECRET_KEY',
|
'secret_key' => 'SECRET_KEY',
|
||||||
'domain' => '空间域名'
|
'domain' => '空间域名'
|
||||||
],
|
],
|
||||||
|
'encrypt_params' => ['secret_key'],
|
||||||
'component' => '/src/app/views/setting/components/storage-qiniu.vue',
|
'component' => '/src/app/views/setting/components/storage-qiniu.vue',
|
||||||
],
|
],
|
||||||
|
|
||||||
@ -67,6 +68,7 @@ class StorageDict
|
|||||||
'endpoint' => 'Endpoint',
|
'endpoint' => 'Endpoint',
|
||||||
'domain' => '空间域名'
|
'domain' => '空间域名'
|
||||||
],
|
],
|
||||||
|
'encrypt_params' => ['secret_key'],
|
||||||
'component' => '/src/app/views/setting/components/storage-ali.vue',
|
'component' => '/src/app/views/setting/components/storage-ali.vue',
|
||||||
],
|
],
|
||||||
|
|
||||||
@ -80,6 +82,7 @@ class StorageDict
|
|||||||
'secret_key' => 'SECRET_KEY',
|
'secret_key' => 'SECRET_KEY',
|
||||||
'domain' => '空间域名'
|
'domain' => '空间域名'
|
||||||
],
|
],
|
||||||
|
'encrypt_params' => ['secret_key'],
|
||||||
'component' => '/src/app/views/setting/components/storage-tencent.vue',
|
'component' => '/src/app/views/setting/components/storage-tencent.vue',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@ -923,6 +923,7 @@ CREATE TABLE `sys_user_role` (
|
|||||||
`create_time` int(11) NOT NULL DEFAULT 0 COMMENT '添加时间',
|
`create_time` int(11) NOT NULL DEFAULT 0 COMMENT '添加时间',
|
||||||
`is_admin` int(11) NOT NULL DEFAULT 0 COMMENT '是否是超级管理员',
|
`is_admin` int(11) NOT NULL DEFAULT 0 COMMENT '是否是超级管理员',
|
||||||
`status` int(11) NOT NULL DEFAULT 1 COMMENT '状态',
|
`status` int(11) NOT NULL DEFAULT 1 COMMENT '状态',
|
||||||
|
`delete_time` INT(11) NOT NULL DEFAULT 0 COMMENT '删除时间',
|
||||||
PRIMARY KEY (`id`) USING BTREE
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户权限表' ROW_FORMAT = Dynamic;
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户权限表' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
@ -1036,7 +1037,7 @@ UPDATE `site` SET site_id = 0 WHERE site_id = 1;
|
|||||||
|
|
||||||
INSERT INTO `sys_user` VALUES ('1', '', '', '', '', '', '0', '0', '0', '1', '0', '0', '0');
|
INSERT INTO `sys_user` VALUES ('1', '', '', '', '', '', '0', '0', '0', '1', '0', '0', '0');
|
||||||
|
|
||||||
INSERT INTO `sys_user_role` VALUES ('1', '1', '0', '', '0', '1', '1');
|
INSERT INTO `sys_user_role` VALUES ('1', '1', '0', '', '0', '1', '1', '0');
|
||||||
|
|
||||||
INSERT INTO `sys_area` VALUES
|
INSERT INTO `sys_area` VALUES
|
||||||
(110000, 0, '北京市', '北京', '116.40529', '39.904987', 1, 0, 1),
|
(110000, 0, '北京市', '北京', '116.40529', '39.904987', 1, 0, 1),
|
||||||
|
|||||||
@ -84,6 +84,7 @@ return [
|
|||||||
//插件安装相关
|
//插件安装相关
|
||||||
'REPEAT_INSTALL' => '当前插件已安装,不能重复安装',
|
'REPEAT_INSTALL' => '当前插件已安装,不能重复安装',
|
||||||
'NOT_UNINSTALL' => '当前插件未安装,不能进行卸载操作',
|
'NOT_UNINSTALL' => '当前插件未安装,不能进行卸载操作',
|
||||||
|
'ADDON_INFO_FILE_NOT_EXIST' => '未找到插件的info.json文件',
|
||||||
|
|
||||||
//菜单管理
|
//菜单管理
|
||||||
'MENU_NOT_EXIST' => '菜单不存在',
|
'MENU_NOT_EXIST' => '菜单不存在',
|
||||||
@ -183,6 +184,7 @@ return [
|
|||||||
'KEYWORDS_NOT_EXIST' => '关键词回复不存在',
|
'KEYWORDS_NOT_EXIST' => '关键词回复不存在',
|
||||||
'WECHAT_EMPOWER_NOT_EXIST' => '微信授权信息不存在',
|
'WECHAT_EMPOWER_NOT_EXIST' => '微信授权信息不存在',
|
||||||
'SCAN_SUCCESS' => '扫码成功',
|
'SCAN_SUCCESS' => '扫码成功',
|
||||||
|
'WECHAT_SNAPSHOUTUSER' => '返回的是虚拟账号',
|
||||||
//小程序
|
//小程序
|
||||||
'WEAPP_NOT_EXIST' => '微信小程序未配置完善',
|
'WEAPP_NOT_EXIST' => '微信小程序未配置完善',
|
||||||
'WEAPP_EMPOWER_NOT_EXIST' => '微信小程序授信信息不存在',
|
'WEAPP_EMPOWER_NOT_EXIST' => '微信小程序授信信息不存在',
|
||||||
|
|||||||
@ -73,7 +73,7 @@ class Site extends BaseModel
|
|||||||
public function searchKeywordsAttr($query, $value, $data)
|
public function searchKeywordsAttr($query, $value, $data)
|
||||||
{
|
{
|
||||||
if ($value != '') {
|
if ($value != '') {
|
||||||
$query->where('site_name|keywords', 'like', '%' . $this->handelSpecialCharacter($value) . '%');
|
$query->where('site_id|site_name|keywords', 'like', '%' . $this->handelSpecialCharacter($value) . '%');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -79,7 +79,7 @@ class SysSchedule extends BaseModel
|
|||||||
*/
|
*/
|
||||||
public function searchStatusAttr(Query $query, $value, $data)
|
public function searchStatusAttr(Query $query, $value, $data)
|
||||||
{
|
{
|
||||||
if ($value) {
|
if ($value != 'all') {
|
||||||
$query->where('status', $value);
|
$query->where('status', $value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ namespace app\model\sys;
|
|||||||
use app\dict\sys\UserDict;
|
use app\dict\sys\UserDict;
|
||||||
use app\model\site\Site;
|
use app\model\site\Site;
|
||||||
use core\base\BaseModel;
|
use core\base\BaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
use think\model\relation\HasOne;
|
use think\model\relation\HasOne;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,6 +25,8 @@ use think\model\relation\HasOne;
|
|||||||
class SysUserRole extends BaseModel
|
class SysUserRole extends BaseModel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
use SoftDelete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据表主键
|
* 数据表主键
|
||||||
* @var string
|
* @var string
|
||||||
@ -41,6 +44,18 @@ class SysUserRole extends BaseModel
|
|||||||
// 设置JSON数据返回数组
|
// 设置JSON数据返回数组
|
||||||
protected $jsonAssoc = true;
|
protected $jsonAssoc = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定义软删除标记字段
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $deleteTime = 'delete_time';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定义软删除字段的默认值
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $defaultSoftDelete = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关联查询用户信息
|
* 关联查询用户信息
|
||||||
* @return HasOne
|
* @return HasOne
|
||||||
|
|||||||
@ -38,49 +38,50 @@ class AuthService extends BaseAdminService
|
|||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return true
|
* @return true
|
||||||
*/
|
*/
|
||||||
public function checkSiteAuth(Request $request){
|
public function checkSiteAuth(Request $request)
|
||||||
|
{
|
||||||
$site_id = $request->adminSiteId();
|
$site_id = $request->adminSiteId();
|
||||||
//todo 将站点编号转化为站点id
|
//todo 将站点编号转化为站点id
|
||||||
$site_info = (new CoreSiteService())->getSiteCache($site_id);
|
$site_info = ( new CoreSiteService() )->getSiteCache($site_id);
|
||||||
//站点不存在
|
//站点不存在
|
||||||
if(empty($site_info)) throw new AuthException('SITE_NOT_EXIST');
|
if (empty($site_info)) throw new AuthException('SITE_NOT_EXIST');
|
||||||
//没有当前站点的信息
|
//没有当前站点的信息
|
||||||
if (!AuthService::isSuperAdmin()) {
|
if (!AuthService::isSuperAdmin()) {
|
||||||
if(!$this->getAuthRole($site_id)) throw new AuthException('NO_SITE_PERMISSION');
|
if (!$this->getAuthRole($site_id)) throw new AuthException('NO_SITE_PERMISSION');
|
||||||
}
|
}
|
||||||
|
|
||||||
$request->siteId($site_id);
|
$request->siteId($site_id);
|
||||||
$request->appType($site_info['app_type']);
|
$request->appType($site_info[ 'app_type' ]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验权限
|
* 校验权限
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function checkRole(Request $request){
|
public function checkRole(Request $request)
|
||||||
|
{
|
||||||
|
|
||||||
$rule = strtolower(trim($request->rule()->getRule()));
|
$rule = strtolower(trim($request->rule()->getRule()));
|
||||||
$method = strtolower(trim($request->method()));
|
$method = strtolower(trim($request->method()));
|
||||||
$site_info = (new AuthSiteService())->getSiteInfo();
|
$site_info = ( new AuthSiteService() )->getSiteInfo();
|
||||||
if($method != 'get'){
|
if ($method != 'get') {
|
||||||
if($site_info['status'] == SiteDict::EXPIRE) throw new AuthException('SITE_EXPIRE_NOT_ALLOW');
|
if ($site_info[ 'status' ] == SiteDict::EXPIRE) throw new AuthException('SITE_EXPIRE_NOT_ALLOW');
|
||||||
if($site_info['status'] == SiteDict::CLOSE) throw new AuthException('SITE_CLOSE_NOT_ALLOW');
|
if ($site_info[ 'status' ] == SiteDict::CLOSE) throw new AuthException('SITE_CLOSE_NOT_ALLOW');
|
||||||
}
|
}
|
||||||
|
|
||||||
$menu_service = new MenuService();
|
$menu_service = new MenuService();
|
||||||
$all_menu_list = $menu_service->getAllApiList($this->app_type);
|
$all_menu_list = $menu_service->getAllApiList($this->app_type);
|
||||||
|
|
||||||
//先判断当前访问的接口是否收到权限的限制
|
//先判断当前访问的接口是否收到权限的限制
|
||||||
$method_menu_list = $all_menu_list[$method] ?? [];
|
$method_menu_list = $all_menu_list[ $method ] ?? [];
|
||||||
if(!in_array($rule, $method_menu_list)) {
|
if (!in_array($rule, $method_menu_list)) {
|
||||||
$other_menu_list = $menu_service->getAllApiList($this->app_type == AppTypeDict::ADMIN ? AppTypeDict::SITE : AppTypeDict::ADMIN);
|
$other_menu_list = $menu_service->getAllApiList($this->app_type == AppTypeDict::ADMIN ? AppTypeDict::SITE : AppTypeDict::ADMIN);
|
||||||
$method_menu_list = $other_menu_list[$method] ?? [];
|
$method_menu_list = $other_menu_list[ $method ] ?? [];
|
||||||
if(!in_array($rule, $method_menu_list)) {
|
if (!in_array($rule, $method_menu_list)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
throw new AuthException('NO_PERMISSION');
|
throw new AuthException('NO_PERMISSION');
|
||||||
@ -88,7 +89,7 @@ class AuthService extends BaseAdminService
|
|||||||
}
|
}
|
||||||
|
|
||||||
$auth_role_list = $this->getAuthApiList();
|
$auth_role_list = $this->getAuthApiList();
|
||||||
if(!empty($auth_role_list[$method]) && in_array($rule, $auth_role_list[$method]))
|
if (!empty($auth_role_list[ $method ]) && in_array($rule, $auth_role_list[ $method ]))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
throw new AuthException('NO_PERMISSION');
|
throw new AuthException('NO_PERMISSION');
|
||||||
@ -99,7 +100,8 @@ class AuthService extends BaseAdminService
|
|||||||
* 获取授权用户的权限信息
|
* 获取授权用户的权限信息
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getAuthRole(int $site_id){
|
public function getAuthRole(int $site_id)
|
||||||
|
{
|
||||||
$user_role_service = new UserRoleService();
|
$user_role_service = new UserRoleService();
|
||||||
return $user_role_service->getUserRole($site_id, $this->uid);
|
return $user_role_service->getUserRole($site_id, $this->uid);
|
||||||
}
|
}
|
||||||
@ -108,7 +110,8 @@ class AuthService extends BaseAdminService
|
|||||||
* 当前授权用户接口权限
|
* 当前授权用户接口权限
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getAuthApiList(){
|
public function getAuthApiList()
|
||||||
|
{
|
||||||
if (AuthService::isSuperAdmin()) {
|
if (AuthService::isSuperAdmin()) {
|
||||||
$is_admin = 1;
|
$is_admin = 1;
|
||||||
} else {
|
} else {
|
||||||
@ -116,15 +119,15 @@ class AuthService extends BaseAdminService
|
|||||||
if (empty($user_role_info))
|
if (empty($user_role_info))
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
$is_admin = $user_role_info['is_admin'];//是否是超级管理员组
|
$is_admin = $user_role_info[ 'is_admin' ];//是否是超级管理员组
|
||||||
}
|
}
|
||||||
|
|
||||||
$menu_service = new MenuService();
|
$menu_service = new MenuService();
|
||||||
if($is_admin){//查询全部启用的权限
|
if ($is_admin) {//查询全部启用的权限
|
||||||
//获取站点信息
|
//获取站点信息
|
||||||
return (new AuthSiteService())->getApiList(1);
|
return ( new AuthSiteService() )->getApiList(1);
|
||||||
}else{
|
} else {
|
||||||
$user_role_ids = $user_role_info['role_ids'];
|
$user_role_ids = $user_role_info[ 'role_ids' ];
|
||||||
$role_service = new RoleService();
|
$role_service = new RoleService();
|
||||||
$menu_keys = $role_service->getMenuIdsByRoleIds($this->site_id, $user_role_ids);
|
$menu_keys = $role_service->getMenuIdsByRoleIds($this->site_id, $user_role_ids);
|
||||||
|
|
||||||
@ -137,21 +140,23 @@ class AuthService extends BaseAdminService
|
|||||||
* 当前授权用户菜单权限
|
* 当前授权用户菜单权限
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getAuthMenuList(int $is_tree = 0, $addon = 'all'){
|
public function getAuthMenuList(int $is_tree = 0, $addon = 'all')
|
||||||
|
{
|
||||||
if (AuthService::isSuperAdmin()) {
|
if (AuthService::isSuperAdmin()) {
|
||||||
$is_admin = 1;
|
$is_admin = 1;
|
||||||
} else {
|
} else {
|
||||||
$user_role_info = $this->getAuthRole($this->site_id);
|
$user_role_info = $this->getAuthRole($this->site_id);
|
||||||
if(empty($user_role_info))
|
if (empty($user_role_info))
|
||||||
return [];
|
return [];
|
||||||
$is_admin = $user_role_info['is_admin'];//是否是超级管理员组
|
$is_admin = $user_role_info[ 'is_admin' ];//是否是超级管理员组
|
||||||
}
|
}
|
||||||
|
|
||||||
$menu_service = new MenuService();
|
$menu_service = new MenuService();
|
||||||
if($is_admin){//查询全部启用的权限
|
if ($is_admin) {
|
||||||
|
// 查询全部启用的权限
|
||||||
return ( new MenuService() )->getAllMenuList($this->app_type, 1, $is_tree, 1);
|
return ( new MenuService() )->getAllMenuList($this->app_type, 1, $is_tree, 1);
|
||||||
}else{
|
} else {
|
||||||
$user_role_ids = $user_role_info['role_ids'];
|
$user_role_ids = $user_role_info[ 'role_ids' ];
|
||||||
$role_service = new RoleService();
|
$role_service = new RoleService();
|
||||||
$menu_keys = $role_service->getMenuIdsByRoleIds($this->site_id, $user_role_ids);
|
$menu_keys = $role_service->getMenuIdsByRoleIds($this->site_id, $user_role_ids);
|
||||||
return $menu_service->getMenuListByMenuKeys($this->site_id, $menu_keys, $this->app_type, $is_tree, $addon);
|
return $menu_service->getMenuListByMenuKeys($this->site_id, $menu_keys, $this->app_type, $is_tree, $addon);
|
||||||
@ -161,8 +166,9 @@ class AuthService extends BaseAdminService
|
|||||||
/**
|
/**
|
||||||
* 获取授权用户信息
|
* 获取授权用户信息
|
||||||
*/
|
*/
|
||||||
public function getAuthInfo(){
|
public function getAuthInfo()
|
||||||
return (new SiteUserService())->getInfo($this->uid);
|
{
|
||||||
|
return ( new SiteUserService() )->getInfo($this->uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -171,8 +177,9 @@ class AuthService extends BaseAdminService
|
|||||||
* @param $data
|
* @param $data
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function modifyAuth(string $field, $data){
|
public function modifyAuth(string $field, $data)
|
||||||
return (new SiteUserService())->modify($this->uid, $field, $data);
|
{
|
||||||
|
return ( new SiteUserService() )->modify($this->uid, $field, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -180,33 +187,35 @@ class AuthService extends BaseAdminService
|
|||||||
* @param array $data
|
* @param array $data
|
||||||
* @return true
|
* @return true
|
||||||
*/
|
*/
|
||||||
public function editAuth(array $data){
|
public function editAuth(array $data)
|
||||||
if(!empty($data['password'])){
|
{
|
||||||
|
if (!empty($data[ 'password' ])) {
|
||||||
//检测原始密码是否正确
|
//检测原始密码是否正确
|
||||||
$user = (new UserService())->find($this->uid);
|
$user = ( new UserService() )->find($this->uid);
|
||||||
if(!check_password($data['original_password'], $user->password))
|
if (!check_password($data[ 'original_password' ], $user->password))
|
||||||
throw new AuthException('OLD_PASSWORD_ERROR');
|
throw new AuthException('OLD_PASSWORD_ERROR');
|
||||||
|
|
||||||
}
|
}
|
||||||
return (new UserService())->edit($this->uid, $data);
|
return ( new UserService() )->edit($this->uid, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否是超级管理员
|
* 是否是超级管理员
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function isSuperAdmin() {
|
public static function isSuperAdmin()
|
||||||
|
{
|
||||||
$super_admin_uid = Cache::get('super_admin_uid');
|
$super_admin_uid = Cache::get('super_admin_uid');
|
||||||
|
|
||||||
if (!$super_admin_uid) {
|
if (!$super_admin_uid) {
|
||||||
$super_admin_uid = (new SysUserRole())->where([
|
$super_admin_uid = ( new SysUserRole() )->where([
|
||||||
['site_id', '=', request()->defaultSiteId()],
|
[ 'site_id', '=', request()->defaultSiteId() ],
|
||||||
['is_admin', '=', 1]
|
[ 'is_admin', '=', 1 ]
|
||||||
])->value('uid');
|
])->value('uid');
|
||||||
Cache::set('super_admin_uid', $super_admin_uid);
|
Cache::set('super_admin_uid', $super_admin_uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $super_admin_uid == (new self())->uid;
|
return $super_admin_uid == ( new self() )->uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ namespace app\service\admin\auth;
|
|||||||
|
|
||||||
use app\dict\sys\AppTypeDict;
|
use app\dict\sys\AppTypeDict;
|
||||||
use app\model\sys\SysUser;
|
use app\model\sys\SysUser;
|
||||||
|
use app\model\sys\SysUserRole;
|
||||||
use app\service\admin\captcha\CaptchaService;
|
use app\service\admin\captcha\CaptchaService;
|
||||||
use app\service\admin\site\SiteService;
|
use app\service\admin\site\SiteService;
|
||||||
use app\service\admin\user\UserRoleService;
|
use app\service\admin\user\UserRoleService;
|
||||||
@ -208,4 +209,20 @@ class LoginService extends BaseAdminService
|
|||||||
return $token_info;
|
return $token_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置管理员密码
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function resetAdministratorPassword() {
|
||||||
|
$super_admin_uid = ( new SysUserRole() )->where([
|
||||||
|
[ 'site_id', '=', request()->defaultSiteId() ],
|
||||||
|
[ 'is_admin', '=', 1 ]
|
||||||
|
])->value('uid');
|
||||||
|
|
||||||
|
$user = (new UserService())->find($super_admin_uid);
|
||||||
|
$user->password = create_password('123456');
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
self::clearToken($super_admin_uid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,7 +35,13 @@ class DiyConfigService extends BaseAdminService
|
|||||||
$list = ( new CoreDiyConfigService() )->getBottomList($params);
|
$list = ( new CoreDiyConfigService() )->getBottomList($params);
|
||||||
|
|
||||||
$site_addon = ( new CoreSiteService() )->getSiteCache($this->site_id);
|
$site_addon = ( new CoreSiteService() )->getSiteCache($this->site_id);
|
||||||
|
$bottom_list_keys = array_column($list, 'key');
|
||||||
|
// 排除没有底部导航的应用
|
||||||
|
foreach ($site_addon[ 'apps' ] as $k => $v) {
|
||||||
|
if (!in_array($v[ 'key' ], $bottom_list_keys)) {
|
||||||
|
unset($site_addon[ 'apps' ][ $k ]);
|
||||||
|
}
|
||||||
|
}
|
||||||
// 单应用,排除 系统 底部导航设置
|
// 单应用,排除 系统 底部导航设置
|
||||||
if (count($list) > 1 && count($site_addon[ 'apps' ]) == 1) {
|
if (count($list) > 1 && count($site_addon[ 'apps' ]) == 1) {
|
||||||
foreach ($list as $k => $v) {
|
foreach ($list as $k => $v) {
|
||||||
|
|||||||
@ -376,7 +376,7 @@ class ServiceGenerator extends BaseGenerator
|
|||||||
{
|
{
|
||||||
foreach ($col as $v)
|
foreach ($col as $v)
|
||||||
{
|
{
|
||||||
$content.= PHP_EOL.' $info['."'".$v."'".'] = strval($info['."'".$v."'])";
|
$content.= PHP_EOL.' $info['."'".$v."'".'] = strval($info['."'".$v."']);";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog v-model="showDialog" :title="formData.{PK} ? t('update{UCASE_CLASS_NAME}') : t('add{UCASE_CLASS_NAME}')" width="50%" class="diy-dialog-wrap"
|
<el-dialog v-model="showDialog" :title="formData.{PK} ? t('update{UCASE_CLASS_NAME}') : t('add{UCASE_CLASS_NAME}')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
|
||||||
:destroy-on-close="true">
|
|
||||||
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||||
{FORM_VIEW}
|
{FORM_VIEW}
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|||||||
@ -170,7 +170,7 @@ class AuthSiteService extends BaseAdminService
|
|||||||
'site_name' => $data['site_name'],
|
'site_name' => $data['site_name'],
|
||||||
'uid' => $this->uid,
|
'uid' => $this->uid,
|
||||||
'group_id' => $data['group_id'],
|
'group_id' => $data['group_id'],
|
||||||
'expire_time' => strtotime("+ {$limit['month']} month")
|
'expire_time' => date('Y-m-d H:i:s', strtotime("+ {$limit['month']} month"))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace app\service\admin\notice;
|
namespace app\service\admin\notice;
|
||||||
|
|
||||||
|
use app\dict\common\CommonDict;
|
||||||
use app\dict\sys\SmsDict;
|
use app\dict\sys\SmsDict;
|
||||||
use app\service\core\sys\CoreConfigService;
|
use app\service\core\sys\CoreConfigService;
|
||||||
use core\base\BaseAdminService;
|
use core\base\BaseAdminService;
|
||||||
@ -49,9 +50,13 @@ class SmsService extends BaseAdminService
|
|||||||
$data['name'] = $v['name'];
|
$data['name'] = $v['name'];
|
||||||
foreach ($v['params'] as $k_param => $v_param)
|
foreach ($v['params'] as $k_param => $v_param)
|
||||||
{
|
{
|
||||||
|
$value = $config_type[$k][$k_param] ?? '';
|
||||||
|
$encrypt_params = $sms_type_list[$k]['encrypt_params'] ?? [];
|
||||||
|
if ($value !== '' && in_array($k_param, $encrypt_params)) $value = CommonDict::ENCRYPT_STR;
|
||||||
|
|
||||||
$data['params'][$k_param] = [
|
$data['params'][$k_param] = [
|
||||||
'name' => $v_param,
|
'name' => $v_param,
|
||||||
'value' => $config_type[$k][$k_param] ?? ''
|
'value' => $value
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$data['component'] = $v['component'] ?? '';
|
$data['component'] = $v['component'] ?? '';
|
||||||
@ -83,9 +88,13 @@ class SmsService extends BaseAdminService
|
|||||||
];
|
];
|
||||||
foreach ($sms_type_list[$sms_type]['params'] as $k_param => $v_param)
|
foreach ($sms_type_list[$sms_type]['params'] as $k_param => $v_param)
|
||||||
{
|
{
|
||||||
|
$value = $config_type[$sms_type][$k_param] ?? '';
|
||||||
|
$encrypt_params = $sms_type_list[$sms_type]['encrypt_params'] ?? [];
|
||||||
|
if ($value !== '' && in_array($k_param, $encrypt_params)) $value = CommonDict::ENCRYPT_STR;
|
||||||
|
|
||||||
$data['params'][$k_param] = [
|
$data['params'][$k_param] = [
|
||||||
'name' => $v_param,
|
'name' => $v_param,
|
||||||
'value' => $config_type[$sms_type][$k_param] ?? ''
|
'value' => $value
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return $data;
|
return $data;
|
||||||
@ -119,7 +128,9 @@ class SmsService extends BaseAdminService
|
|||||||
}
|
}
|
||||||
foreach ($sms_type_list[$sms_type]['params'] as $k_param => $v_param)
|
foreach ($sms_type_list[$sms_type]['params'] as $k_param => $v_param)
|
||||||
{
|
{
|
||||||
$config[$sms_type][$k_param] = $data[$k_param] ?? '';
|
$value = $data[$k_param] ?? '';
|
||||||
|
if ($value == CommonDict::ENCRYPT_STR) $value = isset($config[$sms_type]) ? ($config[$sms_type][$k_param] ?? '') : '';
|
||||||
|
$config[$sms_type][$k_param] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (new CoreConfigService())->setConfig($this->site_id, 'SMS', $config);
|
return (new CoreConfigService())->setConfig($this->site_id, 'SMS', $config);
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
namespace app\service\admin\pay;
|
namespace app\service\admin\pay;
|
||||||
|
|
||||||
use app\dict\common\ChannelDict;
|
use app\dict\common\ChannelDict;
|
||||||
|
use app\dict\common\CommonDict;
|
||||||
use app\dict\pay\PayChannelDict;
|
use app\dict\pay\PayChannelDict;
|
||||||
use app\dict\pay\PayDict;
|
use app\dict\pay\PayDict;
|
||||||
use app\model\pay\PayChannel;
|
use app\model\pay\PayChannel;
|
||||||
@ -55,6 +56,7 @@ class PayChannelService extends BaseAdminService
|
|||||||
if (!array_key_exists($channel, ChannelDict::getType())) throw new PayException('CHANNEL_MARK_INVALID');
|
if (!array_key_exists($channel, ChannelDict::getType())) throw new PayException('CHANNEL_MARK_INVALID');
|
||||||
}
|
}
|
||||||
$pay_channel = $this->core_pay_channel_service->find($this->site_id, $where);
|
$pay_channel = $this->core_pay_channel_service->find($this->site_id, $where);
|
||||||
|
|
||||||
if ($pay_channel->isEmpty()) {
|
if ($pay_channel->isEmpty()) {
|
||||||
$data[ 'channel' ] = $channel;
|
$data[ 'channel' ] = $channel;
|
||||||
$data[ 'type' ] = $type;
|
$data[ 'type' ] = $type;
|
||||||
@ -62,7 +64,13 @@ class PayChannelService extends BaseAdminService
|
|||||||
$data[ 'config' ] = $this->getConfigByPayType($data[ 'config' ], $type);
|
$data[ 'config' ] = $this->getConfigByPayType($data[ 'config' ], $type);
|
||||||
$res = $this->model->create($data);
|
$res = $this->model->create($data);
|
||||||
} else {
|
} else {
|
||||||
|
$config = $pay_channel->config;
|
||||||
$data[ 'config' ] = $this->getConfigByPayType($data[ 'config' ], $type);
|
$data[ 'config' ] = $this->getConfigByPayType($data[ 'config' ], $type);
|
||||||
|
foreach ($data[ 'config' ] as $config_k => $config_v) {
|
||||||
|
if ($config_v == CommonDict::ENCRYPT_STR && isset($config[$config_k])) {
|
||||||
|
$data[ 'config' ][$config_k] = $config[$config_k];
|
||||||
|
}
|
||||||
|
}
|
||||||
$pay_channel->save($data);
|
$pay_channel->save($data);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -87,10 +95,21 @@ class PayChannelService extends BaseAdminService
|
|||||||
foreach ($pay_channel_list_temp as $v) {
|
foreach ($pay_channel_list_temp as $v) {
|
||||||
$pay_channel_list[ $v[ 'channel' ] ][ $v[ 'type' ] ] = $v;
|
$pay_channel_list[ $v[ 'channel' ] ][ $v[ 'type' ] ] = $v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$pay_type_list = PayDict::getPayType();
|
||||||
|
|
||||||
foreach ($channel_list as $k => $v) {
|
foreach ($channel_list as $k => $v) {
|
||||||
$temp_item = $pay_channel_list[ $k ] ?? [];
|
$temp_item = $pay_channel_list[ $k ] ?? [];
|
||||||
foreach ($v[ 'pay_type' ] as $item_k => $item_v) {
|
foreach ($v[ 'pay_type' ] as $item_k => $item_v) {
|
||||||
$temp_v_item = $temp_item[ $item_k ] ?? [ 'status' => 0, 'config' => [ 'name' => '' ], 'sort' => 0 ];
|
if (isset($temp_item[ $item_k ])) {
|
||||||
|
$temp_v_item = $temp_item[ $item_k ];
|
||||||
|
$encrypt_params = $pay_type_list[$item_k]['encrypt_params'] ?? [];
|
||||||
|
foreach ($temp_v_item['config'] as $config_k => $config_v) {
|
||||||
|
if ($config_v !== '' && in_array($config_k, $encrypt_params)) $temp_v_item['config'][$config_k] = CommonDict::ENCRYPT_STR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$temp_v_item = [ 'status' => 0, 'config' => [ 'name' => '' ], 'sort' => 0 ];
|
||||||
|
}
|
||||||
$item_v[ 'config' ] = $temp_v_item[ 'config' ];
|
$item_v[ 'config' ] = $temp_v_item[ 'config' ];
|
||||||
$item_v[ 'status' ] = $temp_v_item[ 'status' ];
|
$item_v[ 'status' ] = $temp_v_item[ 'status' ];
|
||||||
$item_v[ 'sort' ] = $temp_v_item[ 'sort' ];
|
$item_v[ 'sort' ] = $temp_v_item[ 'sort' ];
|
||||||
@ -118,7 +137,17 @@ class PayChannelService extends BaseAdminService
|
|||||||
'site_id' => $this->site_id,
|
'site_id' => $this->site_id,
|
||||||
'channel' => $channel
|
'channel' => $channel
|
||||||
);
|
);
|
||||||
return $this->model->where($where)->field('type, channel, config, sort, status')->select()->toArray();
|
$list = $this->model->where($where)->field('type, channel, config, sort, status')->select()->toArray();
|
||||||
|
if (!empty($list)) {
|
||||||
|
$pay_type_list = PayDict::getPayType();
|
||||||
|
foreach ($list as $k => &$v) {
|
||||||
|
$encrypt_params = $pay_type_list[ $v['type'] ]['encrypt_params'] ?? [];
|
||||||
|
foreach ($v['config'] as $config_k => $config_v) {
|
||||||
|
if ($config_v !== '' && in_array($config_k, $encrypt_params)) $v['config'][$config_k] = CommonDict::ENCRYPT_STR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -113,7 +113,8 @@ class SiteService extends BaseAdminService
|
|||||||
'create_time' => time(),
|
'create_time' => time(),
|
||||||
'expire_time' => $data[ 'expire_time' ],
|
'expire_time' => $data[ 'expire_time' ],
|
||||||
'app' => $site_group[ 'app' ],
|
'app' => $site_group[ 'app' ],
|
||||||
'addons' => ''
|
'addons' => '',
|
||||||
|
'status' => strtotime($data[ 'expire_time' ]) > time() ? SiteDict::ON : SiteDict::EXPIRE
|
||||||
];
|
];
|
||||||
Db::startTrans();
|
Db::startTrans();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -21,7 +21,9 @@ use app\service\admin\user\UserRoleService;
|
|||||||
use app\service\admin\user\UserService;
|
use app\service\admin\user\UserService;
|
||||||
use core\base\BaseAdminService;
|
use core\base\BaseAdminService;
|
||||||
use core\exception\AdminException;
|
use core\exception\AdminException;
|
||||||
|
use core\exception\CommonException;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use think\facade\Cache;
|
||||||
use think\facade\Db;
|
use think\facade\Db;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,7 +138,12 @@ class SiteUserService extends BaseAdminService
|
|||||||
['uid', '=', $uid],
|
['uid', '=', $uid],
|
||||||
['site_id', '=', $this->site_id]
|
['site_id', '=', $this->site_id]
|
||||||
];
|
];
|
||||||
SysUserRole::where($where)->delete();
|
$user = (new SysUserRole())->where($where)->findOrEmpty();
|
||||||
|
if ($user->isEmpty()) throw new CommonException('USER_NOT_EXIST');
|
||||||
|
if ($user->is_admin) throw new CommonException("SUPER_ADMIN_NOT_ALLOW_DEL");
|
||||||
|
$user->delete();
|
||||||
|
LoginService::clearToken($uid);
|
||||||
|
Cache::delete('user_role_list_' . $uid);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +154,7 @@ class SiteUserService extends BaseAdminService
|
|||||||
*/
|
*/
|
||||||
public function lock(int $uid){
|
public function lock(int $uid){
|
||||||
(new SysUserRole())->where([ ['uid', '=', $uid], ['site_id', '=', $this->site_id] ])->update(['status' => UserDict::OFF]);
|
(new SysUserRole())->where([ ['uid', '=', $uid], ['site_id', '=', $this->site_id] ])->update(['status' => UserDict::OFF]);
|
||||||
|
Cache::delete('user_role_list_' . $uid);
|
||||||
LoginService::clearToken($uid);
|
LoginService::clearToken($uid);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -158,6 +166,7 @@ class SiteUserService extends BaseAdminService
|
|||||||
*/
|
*/
|
||||||
public function unlock(int $uid){
|
public function unlock(int $uid){
|
||||||
(new SysUserRole())->where([ ['uid', '=', $uid], ['site_id', '=', $this->site_id] ])->update(['status' => UserDict::ON]);
|
(new SysUserRole())->where([ ['uid', '=', $uid], ['site_id', '=', $this->site_id] ])->update(['status' => UserDict::ON]);
|
||||||
|
Cache::delete('user_role_list_' . $uid);
|
||||||
LoginService::clearToken($uid);
|
LoginService::clearToken($uid);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,11 +14,13 @@ namespace app\service\admin\upgrade;
|
|||||||
use app\dict\addon\AddonDict;
|
use app\dict\addon\AddonDict;
|
||||||
use app\model\addon\Addon;
|
use app\model\addon\Addon;
|
||||||
use app\service\admin\install\InstallSystemService;
|
use app\service\admin\install\InstallSystemService;
|
||||||
|
use app\service\admin\sys\ConfigService;
|
||||||
use app\service\core\addon\CoreAddonCloudService;
|
use app\service\core\addon\CoreAddonCloudService;
|
||||||
use app\service\core\addon\CoreAddonInstallService;
|
use app\service\core\addon\CoreAddonInstallService;
|
||||||
use app\service\core\addon\CoreAddonService;
|
use app\service\core\addon\CoreAddonService;
|
||||||
use app\service\core\addon\CoreDependService;
|
use app\service\core\addon\CoreDependService;
|
||||||
use app\service\core\addon\WapTrait;
|
use app\service\core\addon\WapTrait;
|
||||||
|
use app\service\core\channel\CoreH5Service;
|
||||||
use app\service\core\menu\CoreMenuService;
|
use app\service\core\menu\CoreMenuService;
|
||||||
use app\service\core\niucloud\CoreModuleService;
|
use app\service\core\niucloud\CoreModuleService;
|
||||||
use app\service\core\schedule\CoreScheduleInstallService;
|
use app\service\core\schedule\CoreScheduleInstallService;
|
||||||
@ -403,6 +405,10 @@ class UpgradeService extends BaseAdminService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$map = (new ConfigService())->getMap();
|
||||||
|
( new CoreH5Service() )->mapKeyChange($map[ 'key' ]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace app\service\admin\upload;
|
namespace app\service\admin\upload;
|
||||||
|
|
||||||
|
use app\dict\common\CommonDict;
|
||||||
use app\dict\sys\FileDict;
|
use app\dict\sys\FileDict;
|
||||||
use app\dict\sys\StorageDict;
|
use app\dict\sys\StorageDict;
|
||||||
use app\service\core\upload\CoreStorageService;
|
use app\service\core\upload\CoreStorageService;
|
||||||
@ -37,7 +38,27 @@ class StorageConfigService extends BaseAdminService
|
|||||||
*/
|
*/
|
||||||
public function getStorageList()
|
public function getStorageList()
|
||||||
{
|
{
|
||||||
return (new CoreStorageService())->getStorageList($this->site_id);
|
$config_type = (new CoreStorageService())->getStorageConfig($this->site_id);
|
||||||
|
$storage_type_list = StorageDict::getType();
|
||||||
|
$list = [];
|
||||||
|
foreach ($storage_type_list as $k => $v) {
|
||||||
|
$data = [];
|
||||||
|
$data['storage_type'] = $k;
|
||||||
|
$data['is_use'] = $k == $config_type['default'] ? StorageDict::ON : StorageDict::OFF;
|
||||||
|
$data['name'] = $v['name'];
|
||||||
|
$data['component'] = $v['component'];
|
||||||
|
foreach ($v['params'] as $k_param => $v_param) {
|
||||||
|
$value = $config_type[$k][$k_param] ?? '';
|
||||||
|
$encrypt_params = $v['encrypt_params'] ?? [];
|
||||||
|
if ($value !== '' && in_array($k_param, $encrypt_params)) $value = CommonDict::ENCRYPT_STR;
|
||||||
|
$data['params'][$k_param] = [
|
||||||
|
'name' => $v_param,
|
||||||
|
'value' => $value
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$list[] = $data;
|
||||||
|
}
|
||||||
|
return $list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,9 +84,12 @@ class StorageConfigService extends BaseAdminService
|
|||||||
];
|
];
|
||||||
foreach ($storage_type_list[$storage_type]['params'] as $k_param => $v_param)
|
foreach ($storage_type_list[$storage_type]['params'] as $k_param => $v_param)
|
||||||
{
|
{
|
||||||
|
$value = $config_type[$storage_type][$k_param] ?? '';
|
||||||
|
$encrypt_params = $storage_type_list[$storage_type]['encrypt_params'] ?? [];
|
||||||
|
if ($value !== '' && in_array($k_param, $encrypt_params)) $value = CommonDict::ENCRYPT_STR;
|
||||||
$data['params'][$k_param] = [
|
$data['params'][$k_param] = [
|
||||||
'name' => $v_param,
|
'name' => $v_param,
|
||||||
'value' => $config_type[$storage_type][$k_param] ?? ''
|
'value' => $value
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return $data;
|
return $data;
|
||||||
@ -100,14 +124,15 @@ class StorageConfigService extends BaseAdminService
|
|||||||
if($data['is_use'])
|
if($data['is_use'])
|
||||||
{
|
{
|
||||||
$config['default'] = $storage_type;
|
$config['default'] = $storage_type;
|
||||||
}else{
|
}else if ($config['default'] == $storage_type) {
|
||||||
$config['default'] = '';
|
$config['default'] = '';
|
||||||
}
|
}
|
||||||
foreach ($storage_type_list[$storage_type]['params'] as $k_param => $v_param)
|
foreach ($storage_type_list[$storage_type]['params'] as $k_param => $v_param)
|
||||||
{
|
{
|
||||||
$config[$storage_type][$k_param] = $data[$k_param] ?? '';
|
$value = $data[$k_param] ?? '';
|
||||||
|
if ($value == CommonDict::ENCRYPT_STR) $value = isset($config[$storage_type]) ? ($config[$storage_type][$k_param] ?? '') : '';
|
||||||
|
$config[$storage_type][$k_param] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (new CoreConfigService())->setConfig($this->site_id, 'STORAGE', $config);
|
return (new CoreConfigService())->setConfig($this->site_id, 'STORAGE', $config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -257,7 +257,7 @@ class UserService extends BaseAdminService
|
|||||||
$site_num = (new SysUserRole())->where([['uid', '=', $uid], ['site_id', '<>', request()->defaultSiteId() ] ])->count();
|
$site_num = (new SysUserRole())->where([['uid', '=', $uid], ['site_id', '<>', request()->defaultSiteId() ] ])->count();
|
||||||
if ($site_num) throw new CommonException("USER_NOT_ALLOW_DEL");
|
if ($site_num) throw new CommonException("USER_NOT_ALLOW_DEL");
|
||||||
|
|
||||||
$this->model->where([ ['uid', '=', $uid] ])->delete();
|
$this->model->where([ ['uid', '=', $uid] ])->find()->delete();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace app\service\admin\weapp;
|
namespace app\service\admin\weapp;
|
||||||
|
|
||||||
|
use app\dict\common\CommonDict;
|
||||||
use app\model\sys\SysConfig;
|
use app\model\sys\SysConfig;
|
||||||
use app\service\core\weapp\CoreWeappConfigService;
|
use app\service\core\weapp\CoreWeappConfigService;
|
||||||
use core\base\BaseAdminService;
|
use core\base\BaseAdminService;
|
||||||
@ -30,6 +31,11 @@ class WeappConfigService extends BaseAdminService
|
|||||||
public function getWeappConfig()
|
public function getWeappConfig()
|
||||||
{
|
{
|
||||||
$config_info = (new CoreWeappConfigService())->getWeappConfig($this->site_id);
|
$config_info = (new CoreWeappConfigService())->getWeappConfig($this->site_id);
|
||||||
|
foreach ($config_info as $k => $v) {
|
||||||
|
if ($v !== '' && in_array($k, ['app_secret', 'encoding_aes_key'])) {
|
||||||
|
$config_info[$k] = CommonDict::ENCRYPT_STR;
|
||||||
|
}
|
||||||
|
}
|
||||||
return array_merge($config_info, $this->getWeappStaticInfo());
|
return array_merge($config_info, $this->getWeappStaticInfo());
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -40,6 +46,12 @@ class WeappConfigService extends BaseAdminService
|
|||||||
* @return SysConfig|bool|Model
|
* @return SysConfig|bool|Model
|
||||||
*/
|
*/
|
||||||
public function setWeappConfig(array $data){
|
public function setWeappConfig(array $data){
|
||||||
|
$config = (new CoreWeappConfigService())->getWeappConfig($this->site_id);
|
||||||
|
foreach ($data as $k => $v) {
|
||||||
|
if ($v == CommonDict::ENCRYPT_STR) {
|
||||||
|
$data[$k] = $config[$k];
|
||||||
|
}
|
||||||
|
}
|
||||||
return (new CoreWeappConfigService())->setWeappConfig($this->site_id, $data);
|
return (new CoreWeappConfigService())->setWeappConfig($this->site_id, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace app\service\admin\wechat;
|
namespace app\service\admin\wechat;
|
||||||
|
|
||||||
|
use app\dict\common\CommonDict;
|
||||||
use app\model\sys\SysConfig;
|
use app\model\sys\SysConfig;
|
||||||
use app\service\core\wechat\CoreWechatConfigService;
|
use app\service\core\wechat\CoreWechatConfigService;
|
||||||
use core\base\BaseAdminService;
|
use core\base\BaseAdminService;
|
||||||
@ -29,7 +30,13 @@ class WechatConfigService extends BaseAdminService
|
|||||||
*/
|
*/
|
||||||
public function getWechatConfig()
|
public function getWechatConfig()
|
||||||
{
|
{
|
||||||
return (new CoreWechatConfigService())->getWechatConfig($this->site_id);
|
$config_info = (new CoreWechatConfigService())->getWechatConfig($this->site_id);
|
||||||
|
foreach ($config_info as $k => $v) {
|
||||||
|
if ($v !== '' && in_array($k, ['app_secret', 'encoding_aes_key'])) {
|
||||||
|
$config_info[$k] = CommonDict::ENCRYPT_STR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $config_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,6 +45,12 @@ class WechatConfigService extends BaseAdminService
|
|||||||
* @return SysConfig|bool|Model
|
* @return SysConfig|bool|Model
|
||||||
*/
|
*/
|
||||||
public function setWechatConfig(array $data){
|
public function setWechatConfig(array $data){
|
||||||
|
$config = (new CoreWechatConfigService())->getWechatConfig($this->site_id);
|
||||||
|
foreach ($data as $k => $v) {
|
||||||
|
if ($v == CommonDict::ENCRYPT_STR) {
|
||||||
|
$data[$k] = $config[$k];
|
||||||
|
}
|
||||||
|
}
|
||||||
return (new CoreWechatConfigService())->setWechatConfig($this->site_id, $data);
|
return (new CoreWechatConfigService())->setWechatConfig($this->site_id, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,4 +61,4 @@ class WechatConfigService extends BaseAdminService
|
|||||||
public function getWechatStaticInfo(){
|
public function getWechatStaticInfo(){
|
||||||
return (new CoreWechatConfigService())->getWechatStaticInfo($this->site_id);
|
return (new CoreWechatConfigService())->getWechatStaticInfo($this->site_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace app\service\admin\wxoplatform;
|
namespace app\service\admin\wxoplatform;
|
||||||
|
|
||||||
|
use app\dict\common\CommonDict;
|
||||||
use app\model\sys\SysConfig;
|
use app\model\sys\SysConfig;
|
||||||
use app\service\core\wxoplatform\CoreOplatformConfigService;
|
use app\service\core\wxoplatform\CoreOplatformConfigService;
|
||||||
use core\base\BaseAdminService;
|
use core\base\BaseAdminService;
|
||||||
@ -23,13 +24,20 @@ use think\Model;
|
|||||||
*/
|
*/
|
||||||
class OplatformConfigService extends BaseAdminService
|
class OplatformConfigService extends BaseAdminService
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取配置信息
|
* 获取配置信息
|
||||||
* @return array|null
|
* @return array|null
|
||||||
*/
|
*/
|
||||||
public function getConfig()
|
public function getConfig()
|
||||||
{
|
{
|
||||||
return (new CoreOplatformConfigService())->getConfig();
|
$config = (new CoreOplatformConfigService())->getConfig();
|
||||||
|
foreach ($config as $k => $v) {
|
||||||
|
if ($v !== '' && in_array($k, ['app_secret', 'aes_key'])) {
|
||||||
|
$config[$k] = CommonDict::ENCRYPT_STR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,6 +46,12 @@ class OplatformConfigService extends BaseAdminService
|
|||||||
* @return SysConfig|bool|Model
|
* @return SysConfig|bool|Model
|
||||||
*/
|
*/
|
||||||
public function setConfig(array $data){
|
public function setConfig(array $data){
|
||||||
|
$config = (new CoreOplatformConfigService())->getConfig();
|
||||||
|
foreach ($data as $k => $v) {
|
||||||
|
if ($v == CommonDict::ENCRYPT_STR) {
|
||||||
|
$data[$k] = $config[$k];
|
||||||
|
}
|
||||||
|
}
|
||||||
return (new CoreOplatformConfigService())->setConfig($data);
|
return (new CoreOplatformConfigService())->setConfig($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -49,7 +49,7 @@ class WeappVersionService extends BaseAdminService
|
|||||||
*/
|
*/
|
||||||
public function add(array $data = [])
|
public function add(array $data = [])
|
||||||
{
|
{
|
||||||
$site_group = (new SiteGroupService())->getAll();
|
$site_group = (new SiteGroup())->field("group_id, group_name, group_desc, create_time, update_time, app")->order('create_time asc')->select()->toArray();
|
||||||
if (empty($site_group)) throw new CommonException('PLEASE_ADD_FIRST_SITE_GROUP');
|
if (empty($site_group)) throw new CommonException('PLEASE_ADD_FIRST_SITE_GROUP');
|
||||||
|
|
||||||
$site_group_id = $data['site_group_id'] ?? $site_group[0]['group_id'];
|
$site_group_id = $data['site_group_id'] ?? $site_group[0]['group_id'];
|
||||||
|
|||||||
@ -33,7 +33,13 @@ class DiyConfigService extends BaseApiService
|
|||||||
$list = ( new CoreDiyConfigService() )->getBottomList($params);
|
$list = ( new CoreDiyConfigService() )->getBottomList($params);
|
||||||
|
|
||||||
$site_addon = ( new CoreSiteService() )->getSiteCache($this->site_id);
|
$site_addon = ( new CoreSiteService() )->getSiteCache($this->site_id);
|
||||||
|
$bottom_list_keys = array_column($list, 'key');
|
||||||
|
// 排除没有底部导航的应用
|
||||||
|
foreach ($site_addon[ 'apps' ] as $k => $v) {
|
||||||
|
if (!in_array($v[ 'key' ], $bottom_list_keys)) {
|
||||||
|
unset($site_addon[ 'apps' ][ $k ]);
|
||||||
|
}
|
||||||
|
}
|
||||||
// 单应用,排除 系统 底部导航设置
|
// 单应用,排除 系统 底部导航设置
|
||||||
if (count($list) > 1 && count($site_addon[ 'apps' ]) == 1) {
|
if (count($list) > 1 && count($site_addon[ 'apps' ]) == 1) {
|
||||||
foreach ($list as $k => $v) {
|
foreach ($list as $k => $v) {
|
||||||
|
|||||||
@ -79,6 +79,8 @@ class WechatAuthService extends BaseApiService
|
|||||||
}
|
}
|
||||||
$unionid = $userinfo->getRaw()[ 'unionid' ] ?? '';
|
$unionid = $userinfo->getRaw()[ 'unionid' ] ?? '';
|
||||||
if (empty($openid)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST');
|
if (empty($openid)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST');
|
||||||
|
$is_snapshotuser = $userinfo->getRaw()[ 'is_snapshotuser' ] ?? 0;
|
||||||
|
if ($is_snapshotuser == 1) throw new ApiException('WECHAT_SNAPSHOUTUSER');
|
||||||
//todo 这儿还可能会获取用户昵称 头像 性别 ....用以更新会员信息
|
//todo 这儿还可能会获取用户昵称 头像 性别 ....用以更新会员信息
|
||||||
return [ $avatar ?? '', $nickname ?? '', $openid, $unionid ];
|
return [ $avatar ?? '', $nickname ?? '', $openid, $unionid ];
|
||||||
//todo 业务落地
|
//todo 业务落地
|
||||||
|
|||||||
@ -311,6 +311,7 @@ class CoreAddonDevelopService extends CoreAddonBaseService
|
|||||||
{
|
{
|
||||||
$data['key'] = $this->key;
|
$data['key'] = $this->key;
|
||||||
$this->addon_info = $data;
|
$this->addon_info = $data;
|
||||||
|
$this->addon_info['support_version'] = config('version.version');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -164,6 +164,20 @@ class CoreAddonInstallService extends CoreAddonBaseService
|
|||||||
$install_data = $this->getAddonConfig($this->addon);
|
$install_data = $this->getAddonConfig($this->addon);
|
||||||
if (empty($install_data)) throw new AddonException('ADDON_INFO_FILE_NOT_EXIST');
|
if (empty($install_data)) throw new AddonException('ADDON_INFO_FILE_NOT_EXIST');
|
||||||
|
|
||||||
|
$framework_version = config('version.version');
|
||||||
|
$framework_version_arr = explode('.', $framework_version);
|
||||||
|
|
||||||
|
// 检测框架版本是否支持
|
||||||
|
if (!isset($install_data['support_version']) || empty($install_data['support_version']))
|
||||||
|
throw new AddonException('您要安装的插件或应用的info.json文件中未检测到匹配框架当前版本['. $framework_version_arr[0].'.'.$framework_version_arr[1] .'.*]的信息无法安装,<a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3244512" target="blank">点击查看相关手册</a>');
|
||||||
|
|
||||||
|
$support_framework_arr = explode('.', $install_data['support_version']);
|
||||||
|
if ($framework_version_arr[0].$framework_version_arr[1] != $support_framework_arr[0].$support_framework_arr[1]) {
|
||||||
|
if ((float) "$support_framework_arr[0].$support_framework_arr[1]" < (float) "$framework_version_arr[0].$framework_version_arr[1]") {
|
||||||
|
throw new AddonException('您要安装的插件或应用的info.json文件中检测到支持的框架版本['. $install_data['support_version'] .']低于当前框架版本['. $framework_version_arr[0].'.'.$framework_version_arr[1] .'.*]无法安装,<a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3244512" target="blank">点击查看相关手册</a>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$check_res = Cache::get($this->cache_key . '_install_check');
|
$check_res = Cache::get($this->cache_key . '_install_check');
|
||||||
if (!$check_res) throw new CommonException('INSTALL_CHECK_NOT_PASS');
|
if (!$check_res) throw new CommonException('INSTALL_CHECK_NOT_PASS');
|
||||||
|
|
||||||
|
|||||||
@ -6,5 +6,6 @@
|
|||||||
"author": "{author}",
|
"author": "{author}",
|
||||||
"type": "{type}",
|
"type": "{type}",
|
||||||
"support_app": "{support_app}",
|
"support_app": "{support_app}",
|
||||||
"compile":[]
|
"compile":[],
|
||||||
|
"support_version": "{support_version}"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -229,4 +229,4 @@ class CoreScheduleService extends BaseCoreService
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -188,6 +188,7 @@ class CoreExportService extends BaseCoreService
|
|||||||
{
|
{
|
||||||
$sheet->getColumnDimension($v['excel_column_name'])->setAutoSize(true);
|
$sheet->getColumnDimension($v['excel_column_name'])->setAutoSize(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存Excel文件
|
// 保存Excel文件
|
||||||
$writer = new Xlsx($spreadsheet);
|
$writer = new Xlsx($spreadsheet);
|
||||||
// 导出文件的路径
|
// 导出文件的路径
|
||||||
|
|||||||
3
niucloud/app/upgrade/v052/upgrade.sql
Normal file
3
niucloud/app/upgrade/v052/upgrade.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
ALTER TABLE `sys_user_role`
|
||||||
|
ADD COLUMN delete_time INT(11) NOT NULL DEFAULT 0 COMMENT '删除时间';
|
||||||
@ -13,12 +13,12 @@ $data = [
|
|||||||
'queue:work' => 'app\command\queue\Queue',
|
'queue:work' => 'app\command\queue\Queue',
|
||||||
'queue:restart' => 'app\command\queue\Queue',
|
'queue:restart' => 'app\command\queue\Queue',
|
||||||
'queue:listen' => 'app\command\queue\Queue',
|
'queue:listen' => 'app\command\queue\Queue',
|
||||||
|
|
||||||
//计划任务 自定义命令
|
//计划任务 自定义命令
|
||||||
'cron:schedule' => 'app\command\schedule\Schedule',
|
'cron:schedule' => 'app\command\schedule\Schedule',
|
||||||
|
|
||||||
//wokrerman的启动停止和重启
|
//wokrerman的启动停止和重启
|
||||||
'workerman' => 'app\command\workerman\Workerman',
|
'workerman' => 'app\command\workerman\Workerman',
|
||||||
|
//重置管理员密码
|
||||||
|
'reset:password' => 'app\command\Resetpassword'
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
return (new DictLoader("Console"))->load($data);
|
return (new DictLoader("Console"))->load($data);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'version' => '0.5.1',
|
'version' => '0.5.2',
|
||||||
'code' => '202408160001'
|
'code' => '202409120001'
|
||||||
];
|
];
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
import{d as l,r as d,o as i,c as p,a as t,b as u,e as m,w as f,u as x,f as v,E as h,p as b,g,h as I,i as w,t as S}from"./index-0b016134.js";/* empty css */import{_ as B}from"./_plugin-vue_export-helper-c27b6911.js";const k=""+new URL("error-e4bc1756.png",import.meta.url).href,o=e=>(b("data-v-8fc03fb0"),e=e(),g(),e),y={class:"error"},C={class:"flex items-center"},E=o(()=>t("div",null,[t("img",{class:"w-[300px]",src:k})],-1)),N={class:"text-left ml-[100px]"},R=o(()=>t("div",{class:"error-text text-[28px] font-bold"},"404错误!",-1)),U=o(()=>t("div",{class:"text-[#222] text-[20px] mt-[15px]"},"哎呀,出错了!您访问的页面不存在...",-1)),V=o(()=>t("div",{class:"text-[#c4c2c2] text-[12px] mt-[5px]"},"尝试检查URL的错误,然后点击浏览器刷新按钮。",-1)),L={class:"mt-[40px]"},$=l({__name:"404",setup(e){let s=null;const c=d(5),a=v();return s=setInterval(()=>{c.value===0?(clearInterval(s),a.go(-1)):c.value--},1e3),i(()=>{s&&clearInterval(s)}),(r,n)=>{const _=h;return I(),p("div",y,[t("div",C,[u(r.$slots,"content",{},()=>[E],!0),t("div",N,[R,U,V,t("div",L,[m(_,{class:"bottom",onClick:n[0]||(n[0]=D=>x(a).go(-1))},{default:f(()=>[w(S(c.value)+" 秒后返回上一页",1)]),_:1})])])])])}}});const z=B($,[["__scopeId","data-v-8fc03fb0"]]);export{z as default};
|
import{d as l,r as d,o as i,c as p,a as t,b as u,e as m,w as f,u as x,f as v,E as h,p as b,g,h as I,i as w,t as S}from"./index-29db729d.js";/* empty css */import{_ as B}from"./_plugin-vue_export-helper-c27b6911.js";const k=""+new URL("error-e4bc1756.png",import.meta.url).href,o=e=>(b("data-v-8fc03fb0"),e=e(),g(),e),y={class:"error"},C={class:"flex items-center"},E=o(()=>t("div",null,[t("img",{class:"w-[300px]",src:k})],-1)),N={class:"text-left ml-[100px]"},R=o(()=>t("div",{class:"error-text text-[28px] font-bold"},"404错误!",-1)),U=o(()=>t("div",{class:"text-[#222] text-[20px] mt-[15px]"},"哎呀,出错了!您访问的页面不存在...",-1)),V=o(()=>t("div",{class:"text-[#c4c2c2] text-[12px] mt-[5px]"},"尝试检查URL的错误,然后点击浏览器刷新按钮。",-1)),L={class:"mt-[40px]"},$=l({__name:"404",setup(e){let s=null;const c=d(5),a=v();return s=setInterval(()=>{c.value===0?(clearInterval(s),a.go(-1)):c.value--},1e3),i(()=>{s&&clearInterval(s)}),(r,n)=>{const _=h;return I(),p("div",y,[t("div",C,[u(r.$slots,"content",{},()=>[E],!0),t("div",N,[R,U,V,t("div",L,[m(_,{class:"bottom",onClick:n[0]||(n[0]=D=>x(a).go(-1))},{default:f(()=>[w(S(c.value)+" 秒后返回上一页",1)]),_:1})])])])])}}});const z=B($,[["__scopeId","data-v-8fc03fb0"]]);export{z as default};
|
||||||
@ -1 +0,0 @@
|
|||||||
import{cN as f}from"./index-0b016134.js";export{f as default};
|
|
||||||
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