fix(stats/self_input): 修复保存不入库/路由 404,补全部门与自媒体来源下拉
- 模型去掉 defaultSoftDelete=0,避免 ThinkPHP 软删过滤导致新增记录"隐形" - 菜单 paths 改相对路径并新增「自录数据统计」目录,迁移已有菜单 - Lists/Overview 补部门关联、支持按部门筛选 - 数据权限改由 self_input_stats_view_all_roles 白名单 + DataScope 控制, 编辑/删除完全交给按钮权限校验(移除"仅本人可改"硬限制) - 新增 /stats.self_input/mediaSourceOptions 接口,统计页/账户消耗页/录入弹窗 共用 useMediaSourceOptions + MediaSourceSelect,去重动态加载 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,6 +4,11 @@ export function getSelfInputOverview(params: any) {
|
|||||||
return request.get({ url: '/stats.self_input/overview', params })
|
return request.get({ url: '/stats.self_input/overview', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 自媒体来源下拉(业绩+账户消耗已录入值去重) */
|
||||||
|
export function getSelfInputMediaSourceOptions() {
|
||||||
|
return request.get({ url: '/stats.self_input/mediaSourceOptions' })
|
||||||
|
}
|
||||||
|
|
||||||
export function personalYejiLists(params: any) {
|
export function personalYejiLists(params: any) {
|
||||||
return request.get({ url: '/stats.personal_yeji/lists', params })
|
return request.get({ url: '/stats.personal_yeji/lists', params })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<template>
|
||||||
|
<el-select
|
||||||
|
:model-value="modelValue"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:clearable="clearable"
|
||||||
|
:filterable="filterable"
|
||||||
|
:allow-create="allowCreate"
|
||||||
|
:default-first-option="allowCreate"
|
||||||
|
:disabled="disabled"
|
||||||
|
:loading="loading"
|
||||||
|
:class="selectClass"
|
||||||
|
:style="selectStyle"
|
||||||
|
@update:model-value="emit('update:modelValue', $event)"
|
||||||
|
@change="emit('change', $event)"
|
||||||
|
@visible-change="onVisibleChange"
|
||||||
|
>
|
||||||
|
<el-option v-for="item in options" :key="item" :label="item" :value="item" />
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
modelValue?: string
|
||||||
|
options: string[]
|
||||||
|
loading?: boolean
|
||||||
|
placeholder?: string
|
||||||
|
clearable?: boolean
|
||||||
|
filterable?: boolean
|
||||||
|
allowCreate?: boolean
|
||||||
|
disabled?: boolean
|
||||||
|
selectClass?: string
|
||||||
|
selectStyle?: string | Record<string, string>
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
modelValue: '',
|
||||||
|
loading: false,
|
||||||
|
placeholder: '请选择自媒体来源',
|
||||||
|
clearable: true,
|
||||||
|
filterable: true,
|
||||||
|
allowCreate: false,
|
||||||
|
disabled: false,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'update:modelValue': [value: string]
|
||||||
|
change: [value: string]
|
||||||
|
'visible-change': [visible: boolean]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const onVisibleChange = (visible: boolean) => {
|
||||||
|
emit('visible-change', visible)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -21,13 +21,31 @@
|
|||||||
v-model:endTime="queryParams.end_date"
|
v-model:endTime="queryParams.end_date"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="自媒体来源">
|
<el-form-item label="部门">
|
||||||
<el-input
|
<el-tree-select
|
||||||
v-model="queryParams.media_source"
|
v-model="queryParams.dept_id"
|
||||||
placeholder="筛选自媒体来源"
|
:data="deptOptions"
|
||||||
|
node-key="id"
|
||||||
|
:props="deptTreeProps"
|
||||||
|
:default-expand-all="true"
|
||||||
|
check-strictly
|
||||||
|
placeholder="全部部门"
|
||||||
clearable
|
clearable
|
||||||
|
filterable
|
||||||
class="w-[220px]"
|
class="w-[220px]"
|
||||||
@keyup.enter="resetPage"
|
@change="resetPage"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="自媒体来源">
|
||||||
|
<media-source-select
|
||||||
|
v-model="queryParams.media_source"
|
||||||
|
:options="mediaSourceOptions"
|
||||||
|
:loading="mediaSourceLoading"
|
||||||
|
placeholder="全部来源"
|
||||||
|
:allow-create="false"
|
||||||
|
select-class="w-[220px]"
|
||||||
|
@change="resetPage"
|
||||||
|
@visible-change="onMediaSourceDropdownVisible"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item class="w-[280px]" label="备注/录入人">
|
<el-form-item class="w-[280px]" label="备注/录入人">
|
||||||
@@ -41,9 +59,7 @@
|
|||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="resetPage">查询</el-button>
|
<el-button type="primary" @click="resetPage">查询</el-button>
|
||||||
<el-button @click="handleReset">重置</el-button>
|
<el-button @click="handleReset">重置</el-button>
|
||||||
<router-link to="/stats/self_input">
|
<el-button v-if="selfInputPath" class="ml-2" @click="goSelfInput">返回统计</el-button>
|
||||||
<el-button class="ml-2">返回统计</el-button>
|
|
||||||
</router-link>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -66,12 +82,17 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="备注" prop="remark" min-width="200" show-overflow-tooltip />
|
<el-table-column label="备注" prop="remark" min-width="200" show-overflow-tooltip />
|
||||||
<el-table-column label="录入人" prop="creator_name" min-width="100" />
|
<el-table-column label="录入人" prop="creator_name" min-width="100" />
|
||||||
|
<el-table-column label="部门" prop="dept_name" min-width="140" show-overflow-tooltip>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span v-if="row.dept_name">{{ row.dept_name }}</span>
|
||||||
|
<span v-else class="text-gray-400">未分配</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="最后修改人" prop="updater_name" min-width="100" />
|
<el-table-column label="最后修改人" prop="updater_name" min-width="100" />
|
||||||
<el-table-column label="更新时间" prop="update_time" min-width="180" />
|
<el-table-column label="更新时间" prop="update_time" min-width="180" />
|
||||||
<el-table-column label="操作" width="160" fixed="right">
|
<el-table-column label="操作" width="160" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button
|
<el-button
|
||||||
v-if="canMutateRow(row)"
|
|
||||||
v-perms="['stats.personal_account_cost/edit']"
|
v-perms="['stats.personal_account_cost/edit']"
|
||||||
type="primary"
|
type="primary"
|
||||||
link
|
link
|
||||||
@@ -80,7 +101,6 @@
|
|||||||
编辑
|
编辑
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="canMutateRow(row)"
|
|
||||||
v-perms="['stats.personal_account_cost/delete']"
|
v-perms="['stats.personal_account_cost/delete']"
|
||||||
type="danger"
|
type="danger"
|
||||||
link
|
link
|
||||||
@@ -97,26 +117,57 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<cost-edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
|
<cost-edit-popup
|
||||||
|
v-if="showEdit"
|
||||||
|
ref="editRef"
|
||||||
|
:media-source-options="mediaSourceOptions"
|
||||||
|
@success="handleCostSuccess"
|
||||||
|
@close="showEdit = false"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup name="personalAccountCost">
|
<script lang="ts" setup name="personalAccountCost">
|
||||||
import { personalAccountCostDelete, personalAccountCostLists } from '@/api/self_input_stats'
|
import { personalAccountCostDelete, personalAccountCostLists } from '@/api/self_input_stats'
|
||||||
|
import { deptAll } from '@/api/org/department'
|
||||||
import { usePaging } from '@/hooks/usePaging'
|
import { usePaging } from '@/hooks/usePaging'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import { getRoutePath } from '@/router'
|
||||||
import feedback from '@/utils/feedback'
|
import feedback from '@/utils/feedback'
|
||||||
|
|
||||||
import CostEditPopup from './cost-edit.vue'
|
import CostEditPopup from './cost-edit.vue'
|
||||||
|
import MediaSourceSelect from './MediaSourceSelect.vue'
|
||||||
|
import { useMediaSourceOptions } from './useMediaSourceOptions'
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const router = useRouter()
|
||||||
const editRef = shallowRef<InstanceType<typeof CostEditPopup>>()
|
const editRef = shallowRef<InstanceType<typeof CostEditPopup>>()
|
||||||
const showEdit = ref(false)
|
const showEdit = ref(false)
|
||||||
|
const deptOptions = ref<any[]>([])
|
||||||
|
const {
|
||||||
|
mediaSourceOptions,
|
||||||
|
mediaSourceLoading,
|
||||||
|
loadMediaSourceOptions,
|
||||||
|
refreshMediaSourceOptions,
|
||||||
|
} = useMediaSourceOptions()
|
||||||
|
|
||||||
|
const deptTreeProps = {
|
||||||
|
value: 'id',
|
||||||
|
label: 'name',
|
||||||
|
children: 'children',
|
||||||
|
}
|
||||||
|
|
||||||
|
const selfInputPath = computed(() => getRoutePath('stats.self_input/overview') || '')
|
||||||
|
|
||||||
|
const goSelfInput = () => {
|
||||||
|
if (selfInputPath.value) {
|
||||||
|
router.push(selfInputPath.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const queryParams = reactive({
|
const queryParams = reactive({
|
||||||
start_date: '',
|
start_date: '',
|
||||||
end_date: '',
|
end_date: '',
|
||||||
media_source: '',
|
media_source: '',
|
||||||
|
dept_id: undefined as number | undefined,
|
||||||
remark: '',
|
remark: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -125,23 +176,28 @@ const { pager, getLists, resetPage } = usePaging({
|
|||||||
params: queryParams,
|
params: queryParams,
|
||||||
})
|
})
|
||||||
|
|
||||||
const currentAdminId = computed(() => Number(userStore.userInfo?.id || 0))
|
|
||||||
const isRoot = computed(() => Number(userStore.userInfo?.root || 0) === 1)
|
|
||||||
|
|
||||||
const canMutateRow = (row: Record<string, any>) => {
|
|
||||||
if (isRoot.value) return true
|
|
||||||
return Number(row.creator_id) === currentAdminId.value
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
queryParams.start_date = ''
|
queryParams.start_date = ''
|
||||||
queryParams.end_date = ''
|
queryParams.end_date = ''
|
||||||
queryParams.media_source = ''
|
queryParams.media_source = ''
|
||||||
|
queryParams.dept_id = undefined
|
||||||
queryParams.remark = ''
|
queryParams.remark = ''
|
||||||
resetPage()
|
resetPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onMediaSourceDropdownVisible = (visible: boolean) => {
|
||||||
|
if (visible) {
|
||||||
|
refreshMediaSourceOptions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCostSuccess = async () => {
|
||||||
|
await refreshMediaSourceOptions()
|
||||||
|
getLists()
|
||||||
|
}
|
||||||
|
|
||||||
const handleAdd = async () => {
|
const handleAdd = async () => {
|
||||||
|
await refreshMediaSourceOptions()
|
||||||
showEdit.value = true
|
showEdit.value = true
|
||||||
await nextTick()
|
await nextTick()
|
||||||
editRef.value?.open('add')
|
editRef.value?.open('add')
|
||||||
@@ -159,6 +215,22 @@ const handleDelete = async (id: number) => {
|
|||||||
await personalAccountCostDelete({ id })
|
await personalAccountCostDelete({ id })
|
||||||
getLists()
|
getLists()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loadDeptOptions = async () => {
|
||||||
|
try {
|
||||||
|
const res = await deptAll({ apply_data_scope: 1 })
|
||||||
|
if (Array.isArray(res)) {
|
||||||
|
deptOptions.value = res
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
deptOptions.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadDeptOptions()
|
||||||
|
loadMediaSourceOptions()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -20,12 +20,13 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="自媒体来源" prop="media_source">
|
<el-form-item label="自媒体来源" prop="media_source">
|
||||||
<el-input
|
<media-source-select
|
||||||
v-model="formData.media_source"
|
v-model="formData.media_source"
|
||||||
placeholder="如:抖音-账号A"
|
:options="mediaSourceOptions"
|
||||||
maxlength="120"
|
placeholder="请选择或输入自媒体来源"
|
||||||
show-word-limit
|
:allow-create="true"
|
||||||
:disabled="mode === 'edit'"
|
:disabled="mode === 'edit'"
|
||||||
|
select-class="w-full"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="账户消耗" prop="amount">
|
<el-form-item label="账户消耗" prop="amount">
|
||||||
@@ -57,11 +58,21 @@ import type { FormInstance } from 'element-plus'
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
personalAccountCostAdd,
|
personalAccountCostAdd,
|
||||||
personalAccountCostDetail,
|
|
||||||
personalAccountCostEdit,
|
personalAccountCostEdit,
|
||||||
} from '@/api/self_input_stats'
|
} from '@/api/self_input_stats'
|
||||||
import Popup from '@/components/popup/index.vue'
|
import Popup from '@/components/popup/index.vue'
|
||||||
|
|
||||||
|
import MediaSourceSelect from './MediaSourceSelect.vue'
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
mediaSourceOptions?: string[]
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
mediaSourceOptions: () => [],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const emit = defineEmits(['success', 'close'])
|
const emit = defineEmits(['success', 'close'])
|
||||||
const formRef = shallowRef<FormInstance>()
|
const formRef = shallowRef<FormInstance>()
|
||||||
const popupRef = shallowRef<InstanceType<typeof Popup>>()
|
const popupRef = shallowRef<InstanceType<typeof Popup>>()
|
||||||
@@ -116,11 +127,6 @@ const setFormData = (data: Record<string, any>) => {
|
|||||||
formData.remark = data.remark ?? ''
|
formData.remark = data.remark ?? ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDetail = async (row: Record<string, any>) => {
|
|
||||||
const data = await personalAccountCostDetail({ id: row.id })
|
|
||||||
setFormData(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
emit('close')
|
emit('close')
|
||||||
}
|
}
|
||||||
@@ -128,6 +134,5 @@ const handleClose = () => {
|
|||||||
defineExpose({
|
defineExpose({
|
||||||
open,
|
open,
|
||||||
setFormData,
|
setFormData,
|
||||||
getDetail,
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -25,13 +25,32 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="自媒体来源">
|
<el-form-item label="部门">
|
||||||
<el-input
|
<el-tree-select
|
||||||
v-model="queryParams.media_source"
|
v-model="queryParams.dept_id"
|
||||||
placeholder="筛选自媒体来源"
|
:data="deptOptions"
|
||||||
|
node-key="id"
|
||||||
|
:props="deptTreeProps"
|
||||||
|
:default-expand-all="true"
|
||||||
|
check-strictly
|
||||||
|
placeholder="全部部门"
|
||||||
clearable
|
clearable
|
||||||
|
filterable
|
||||||
style="width: 220px"
|
style="width: 220px"
|
||||||
@keyup.enter="handleQuery"
|
@change="handleQuery"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="自媒体来源">
|
||||||
|
<media-source-select
|
||||||
|
v-model="queryParams.media_source"
|
||||||
|
:options="mediaSourceOptions"
|
||||||
|
:loading="mediaSourceLoading"
|
||||||
|
placeholder="全部来源"
|
||||||
|
:allow-create="false"
|
||||||
|
select-style="width: 220px"
|
||||||
|
@change="handleQuery"
|
||||||
|
@visible-change="onMediaSourceDropdownVisible"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@@ -65,12 +84,13 @@
|
|||||||
</template>
|
</template>
|
||||||
新增业绩
|
新增业绩
|
||||||
</el-button>
|
</el-button>
|
||||||
<router-link
|
<el-button
|
||||||
|
v-if="accountCostEntryPath"
|
||||||
v-perms="['stats.personal_account_cost/lists']"
|
v-perms="['stats.personal_account_cost/lists']"
|
||||||
to="/stats/self_input/account_cost"
|
@click="goAccountCostEntry"
|
||||||
>
|
>
|
||||||
<el-button>账户消耗录入</el-button>
|
账户消耗录入
|
||||||
</router-link>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -85,6 +105,12 @@
|
|||||||
<el-table-column label="日期" prop="yeji_date" min-width="110" fixed="left" />
|
<el-table-column label="日期" prop="yeji_date" min-width="110" fixed="left" />
|
||||||
<el-table-column label="自媒体来源" prop="media_source" min-width="140" show-overflow-tooltip />
|
<el-table-column label="自媒体来源" prop="media_source" min-width="140" show-overflow-tooltip />
|
||||||
<el-table-column label="录入人" prop="creator_name" min-width="100" />
|
<el-table-column label="录入人" prop="creator_name" min-width="100" />
|
||||||
|
<el-table-column label="部门" prop="dept_name" min-width="140" show-overflow-tooltip>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span v-if="row.dept_name">{{ row.dept_name }}</span>
|
||||||
|
<span v-else class="text-gray-400">未分配</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-for="col in tableColumns"
|
v-for="col in tableColumns"
|
||||||
:key="col.key"
|
:key="col.key"
|
||||||
@@ -100,7 +126,6 @@
|
|||||||
<el-table-column label="操作" width="140" fixed="right">
|
<el-table-column label="操作" width="140" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button
|
<el-button
|
||||||
v-if="canMutateRow(row)"
|
|
||||||
v-perms="['stats.personal_yeji/edit']"
|
v-perms="['stats.personal_yeji/edit']"
|
||||||
type="primary"
|
type="primary"
|
||||||
link
|
link
|
||||||
@@ -109,7 +134,6 @@
|
|||||||
编辑
|
编辑
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="canMutateRow(row)"
|
|
||||||
v-perms="['stats.personal_yeji/delete']"
|
v-perms="['stats.personal_yeji/delete']"
|
||||||
type="danger"
|
type="danger"
|
||||||
link
|
link
|
||||||
@@ -126,7 +150,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<yeji-edit-popup v-if="showYejiEdit" ref="yejiEditRef" @success="fetchOverview" @close="showYejiEdit = false" />
|
<yeji-edit-popup
|
||||||
|
v-if="showYejiEdit"
|
||||||
|
ref="yejiEditRef"
|
||||||
|
:media-source-options="mediaSourceOptions"
|
||||||
|
@success="handleYejiSuccess"
|
||||||
|
@close="showYejiEdit = false"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -135,11 +165,14 @@ import {
|
|||||||
getSelfInputOverview,
|
getSelfInputOverview,
|
||||||
personalYejiDelete,
|
personalYejiDelete,
|
||||||
} from '@/api/self_input_stats'
|
} from '@/api/self_input_stats'
|
||||||
|
import { deptAll } from '@/api/org/department'
|
||||||
import { usePaging } from '@/hooks/usePaging'
|
import { usePaging } from '@/hooks/usePaging'
|
||||||
import useUserStore from '@/stores/modules/user'
|
import { getRoutePath } from '@/router'
|
||||||
import feedback from '@/utils/feedback'
|
import feedback from '@/utils/feedback'
|
||||||
|
|
||||||
|
import MediaSourceSelect from './MediaSourceSelect.vue'
|
||||||
import YejiEditPopup from './yeji-edit.vue'
|
import YejiEditPopup from './yeji-edit.vue'
|
||||||
|
import { useMediaSourceOptions } from './useMediaSourceOptions'
|
||||||
|
|
||||||
type MetricType = 'count' | 'money' | 'percent' | 'ratio'
|
type MetricType = 'count' | 'money' | 'percent' | 'ratio'
|
||||||
|
|
||||||
@@ -156,10 +189,23 @@ interface MetricColumn {
|
|||||||
minWidth?: number
|
minWidth?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const router = useRouter()
|
||||||
const yejiEditRef = shallowRef<InstanceType<typeof YejiEditPopup>>()
|
const yejiEditRef = shallowRef<InstanceType<typeof YejiEditPopup>>()
|
||||||
const showYejiEdit = ref(false)
|
const showYejiEdit = ref(false)
|
||||||
const dateRange = ref<string[]>([])
|
const dateRange = ref<string[]>([])
|
||||||
|
const deptOptions = ref<any[]>([])
|
||||||
|
const {
|
||||||
|
mediaSourceOptions,
|
||||||
|
mediaSourceLoading,
|
||||||
|
loadMediaSourceOptions,
|
||||||
|
refreshMediaSourceOptions,
|
||||||
|
} = useMediaSourceOptions()
|
||||||
|
|
||||||
|
const deptTreeProps = {
|
||||||
|
value: 'id',
|
||||||
|
label: 'name',
|
||||||
|
children: 'children',
|
||||||
|
}
|
||||||
|
|
||||||
const overview = reactive<Record<string, any>>({
|
const overview = reactive<Record<string, any>>({
|
||||||
date_range: [],
|
date_range: [],
|
||||||
@@ -168,11 +214,20 @@ const overview = reactive<Record<string, any>>({
|
|||||||
|
|
||||||
const queryParams = reactive({
|
const queryParams = reactive({
|
||||||
media_source: '',
|
media_source: '',
|
||||||
|
dept_id: undefined as number | undefined,
|
||||||
time_type: 'today',
|
time_type: 'today',
|
||||||
start_date: '',
|
start_date: '',
|
||||||
end_date: '',
|
end_date: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const accountCostEntryPath = computed(() => getRoutePath('stats.personal_account_cost/lists') || '')
|
||||||
|
|
||||||
|
const goAccountCostEntry = () => {
|
||||||
|
if (accountCostEntryPath.value) {
|
||||||
|
router.push(accountCostEntryPath.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const fetchOverviewList = async (params: Record<string, any>) => {
|
const fetchOverviewList = async (params: Record<string, any>) => {
|
||||||
if (queryParams.time_type === 'custom') {
|
if (queryParams.time_type === 'custom') {
|
||||||
params.start_date = dateRange.value[0] || ''
|
params.start_date = dateRange.value[0] || ''
|
||||||
@@ -183,6 +238,33 @@ const fetchOverviewList = async (params: Record<string, any>) => {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loadDeptOptions = async () => {
|
||||||
|
try {
|
||||||
|
const res = await deptAll({ apply_data_scope: 1 })
|
||||||
|
if (Array.isArray(res)) {
|
||||||
|
deptOptions.value = res
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
deptOptions.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onMediaSourceDropdownVisible = (visible: boolean) => {
|
||||||
|
if (visible) {
|
||||||
|
refreshMediaSourceOptions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleYejiSuccess = async () => {
|
||||||
|
await refreshMediaSourceOptions()
|
||||||
|
await fetchOverview()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadDeptOptions()
|
||||||
|
loadMediaSourceOptions()
|
||||||
|
})
|
||||||
|
|
||||||
const { pager, getLists } = usePaging({
|
const { pager, getLists } = usePaging({
|
||||||
fetchFun: fetchOverviewList,
|
fetchFun: fetchOverviewList,
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
@@ -234,14 +316,6 @@ const dateRangeText = computed(() => {
|
|||||||
return `${overview.date_range[0]} 至 ${overview.date_range[1]}`
|
return `${overview.date_range[0]} 至 ${overview.date_range[1]}`
|
||||||
})
|
})
|
||||||
|
|
||||||
const currentAdminId = computed(() => Number(userStore.userInfo?.id || 0))
|
|
||||||
const isRoot = computed(() => Number(userStore.userInfo?.root || 0) === 1)
|
|
||||||
|
|
||||||
const canMutateRow = (row: Record<string, any>) => {
|
|
||||||
if (isRoot.value) return true
|
|
||||||
return Number(row.creator_id) === currentAdminId.value
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchOverview = async () => {
|
const fetchOverview = async () => {
|
||||||
try {
|
try {
|
||||||
await getLists()
|
await getLists()
|
||||||
@@ -273,6 +347,7 @@ const handleQuery = () => {
|
|||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
queryParams.media_source = ''
|
queryParams.media_source = ''
|
||||||
|
queryParams.dept_id = undefined
|
||||||
queryParams.time_type = 'today'
|
queryParams.time_type = 'today'
|
||||||
dateRange.value = []
|
dateRange.value = []
|
||||||
pager.page = 1
|
pager.page = 1
|
||||||
@@ -289,6 +364,7 @@ const renderMetric = (key: string, source: Record<string, any>, type = 'count')
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleAddYeji = async () => {
|
const handleAddYeji = async () => {
|
||||||
|
await refreshMediaSourceOptions()
|
||||||
showYejiEdit.value = true
|
showYejiEdit.value = true
|
||||||
await nextTick()
|
await nextTick()
|
||||||
yejiEditRef.value?.open('add')
|
yejiEditRef.value?.open('add')
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { getSelfInputMediaSourceOptions } from '@/api/self_input_stats'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自录转化统计:自媒体来源下拉(从已录入业绩/消耗去重,两页共用同一接口)
|
||||||
|
*/
|
||||||
|
export function useMediaSourceOptions() {
|
||||||
|
const mediaSourceOptions = ref<string[]>([])
|
||||||
|
const mediaSourceLoading = ref(false)
|
||||||
|
|
||||||
|
const loadMediaSourceOptions = async (force = false) => {
|
||||||
|
if (!force && mediaSourceOptions.value.length > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mediaSourceLoading.value = true
|
||||||
|
try {
|
||||||
|
const res = await getSelfInputMediaSourceOptions()
|
||||||
|
mediaSourceOptions.value = Array.isArray(res) ? res : []
|
||||||
|
} catch {
|
||||||
|
mediaSourceOptions.value = []
|
||||||
|
} finally {
|
||||||
|
mediaSourceLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const refreshMediaSourceOptions = () => loadMediaSourceOptions(true)
|
||||||
|
|
||||||
|
return {
|
||||||
|
mediaSourceOptions,
|
||||||
|
mediaSourceLoading,
|
||||||
|
loadMediaSourceOptions,
|
||||||
|
refreshMediaSourceOptions,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,12 +20,13 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="自媒体来源" prop="media_source">
|
<el-form-item label="自媒体来源" prop="media_source">
|
||||||
<el-input
|
<media-source-select
|
||||||
v-model="formData.media_source"
|
v-model="formData.media_source"
|
||||||
placeholder="如:抖音-账号A"
|
:options="mediaSourceOptions"
|
||||||
maxlength="120"
|
placeholder="请选择或输入自媒体来源"
|
||||||
show-word-limit
|
:allow-create="true"
|
||||||
:disabled="mode === 'edit'"
|
:disabled="mode === 'edit'"
|
||||||
|
select-class="w-full"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
@@ -129,9 +130,20 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { FormInstance } from 'element-plus'
|
import type { FormInstance } from 'element-plus'
|
||||||
|
|
||||||
import { personalYejiAdd, personalYejiDetail, personalYejiEdit } from '@/api/self_input_stats'
|
import { personalYejiAdd, personalYejiEdit } from '@/api/self_input_stats'
|
||||||
import Popup from '@/components/popup/index.vue'
|
import Popup from '@/components/popup/index.vue'
|
||||||
|
|
||||||
|
import MediaSourceSelect from './MediaSourceSelect.vue'
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
mediaSourceOptions?: string[]
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
mediaSourceOptions: () => [],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const emit = defineEmits(['success', 'close'])
|
const emit = defineEmits(['success', 'close'])
|
||||||
const formRef = shallowRef<FormInstance>()
|
const formRef = shallowRef<FormInstance>()
|
||||||
const popupRef = shallowRef<InstanceType<typeof Popup>>()
|
const popupRef = shallowRef<InstanceType<typeof Popup>>()
|
||||||
@@ -207,11 +219,6 @@ const setFormData = (data: Record<string, any>) => {
|
|||||||
formData.remark = data.remark ?? ''
|
formData.remark = data.remark ?? ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDetail = async (row: Record<string, any>) => {
|
|
||||||
const data = await personalYejiDetail({ id: row.id })
|
|
||||||
setFormData(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
emit('close')
|
emit('close')
|
||||||
}
|
}
|
||||||
@@ -219,6 +226,5 @@ const handleClose = () => {
|
|||||||
defineExpose({
|
defineExpose({
|
||||||
open,
|
open,
|
||||||
setFormData,
|
setFormData,
|
||||||
getDetail,
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -15,4 +15,14 @@ class SelfInputController extends BaseAdminController
|
|||||||
|
|
||||||
return $this->data($result);
|
return $this->data($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自媒体来源下拉:从已录入业绩/账户消耗去重提取(随录入动态变化)
|
||||||
|
*/
|
||||||
|
public function mediaSourceOptions()
|
||||||
|
{
|
||||||
|
$list = SelfInputLogic::mediaSourceOptions($this->adminId, $this->adminInfo);
|
||||||
|
|
||||||
|
return $this->data($list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,6 +132,19 @@ class AuthMiddleware
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 自录转化统计:自媒体来源下拉,复用总览或账户消耗列表权限
|
||||||
|
if ($accessUri === 'stats.selfinput/mediasourceoptions') {
|
||||||
|
$selfInputAliases = [
|
||||||
|
'stats.selfinput/overview',
|
||||||
|
'stats.self_input/overview',
|
||||||
|
'stats.personalaccountcost/lists',
|
||||||
|
'stats.personal_account_cost/lists',
|
||||||
|
];
|
||||||
|
if (count(array_intersect($selfInputAliases, $AdminUris)) > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 处方库列表:消费者开方页/处方库页导入共用,复用开方或处方库菜单权限
|
// 处方库列表:消费者开方页/处方库页导入共用,复用开方或处方库菜单权限
|
||||||
if ($accessUri === 'tcm.prescriptionlibrary/lists'
|
if ($accessUri === 'tcm.prescriptionlibrary/lists'
|
||||||
&& $this->matchPrescriptionLibraryListsPermission($adminUris)) {
|
&& $this->matchPrescriptionLibraryListsPermission($adminUris)) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace app\adminapi\lists\stats;
|
namespace app\adminapi\lists\stats;
|
||||||
|
|
||||||
use app\adminapi\lists\BaseAdminDataLists;
|
use app\adminapi\lists\BaseAdminDataLists;
|
||||||
|
use app\adminapi\logic\stats\PersonalStatsScopeTrait;
|
||||||
use app\common\lists\ListsExtendInterface;
|
use app\common\lists\ListsExtendInterface;
|
||||||
use app\common\lists\ListsSearchInterface;
|
use app\common\lists\ListsSearchInterface;
|
||||||
use app\common\lists\Traits\HasDataScopeFilter;
|
use app\common\lists\Traits\HasDataScopeFilter;
|
||||||
@@ -13,6 +14,7 @@ use app\common\model\stats\PersonalAccountCost;
|
|||||||
class PersonalAccountCostLists extends BaseAdminDataLists implements ListsSearchInterface, ListsExtendInterface
|
class PersonalAccountCostLists extends BaseAdminDataLists implements ListsSearchInterface, ListsExtendInterface
|
||||||
{
|
{
|
||||||
use HasDataScopeFilter;
|
use HasDataScopeFilter;
|
||||||
|
use PersonalStatsScopeTrait;
|
||||||
|
|
||||||
public function setSearch(): array
|
public function setSearch(): array
|
||||||
{
|
{
|
||||||
@@ -24,7 +26,15 @@ class PersonalAccountCostLists extends BaseAdminDataLists implements ListsSearch
|
|||||||
private function baseQuery()
|
private function baseQuery()
|
||||||
{
|
{
|
||||||
$query = PersonalAccountCost::where($this->searchWhere);
|
$query = PersonalAccountCost::where($this->searchWhere);
|
||||||
$this->applyDataScopeByOwner($query, 'creator_id');
|
$visibleIds = $this->getDataScopeVisibleAdminIds();
|
||||||
|
$deptId = (int) ($this->params['dept_id'] ?? 0);
|
||||||
|
|
||||||
|
$finalIds = self::intersectVisibleByDept($visibleIds, $deptId);
|
||||||
|
if ($finalIds === []) {
|
||||||
|
$query->whereRaw('0 = 1');
|
||||||
|
} elseif ($finalIds !== null) {
|
||||||
|
$query->whereIn('creator_id', $finalIds);
|
||||||
|
}
|
||||||
|
|
||||||
if (!empty($this->params['start_date']) && !empty($this->params['end_date'])) {
|
if (!empty($this->params['start_date']) && !empty($this->params['end_date'])) {
|
||||||
$query->whereBetween('cost_date', [$this->params['start_date'], $this->params['end_date']]);
|
$query->whereBetween('cost_date', [$this->params['start_date'], $this->params['end_date']]);
|
||||||
@@ -35,7 +45,7 @@ class PersonalAccountCostLists extends BaseAdminDataLists implements ListsSearch
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($this->params['media_source'])) {
|
if (!empty($this->params['media_source'])) {
|
||||||
$query->whereLike('media_source', '%' . trim((string) $this->params['media_source']) . '%');
|
$query->where('media_source', trim((string) $this->params['media_source']));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
@@ -43,11 +53,13 @@ class PersonalAccountCostLists extends BaseAdminDataLists implements ListsSearch
|
|||||||
|
|
||||||
public function lists(): array
|
public function lists(): array
|
||||||
{
|
{
|
||||||
return $this->baseQuery()
|
$rows = $this->baseQuery()
|
||||||
->order(['cost_date' => 'desc', 'id' => 'desc'])
|
->order(['cost_date' => 'desc', 'id' => 'desc'])
|
||||||
->limit($this->limitOffset, $this->limitLength)
|
->limit($this->limitOffset, $this->limitLength)
|
||||||
->select()
|
->select()
|
||||||
->toArray();
|
->toArray();
|
||||||
|
|
||||||
|
return self::attachDeptInfoToRows($rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function count(): int
|
public function count(): int
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace app\adminapi\lists\stats;
|
namespace app\adminapi\lists\stats;
|
||||||
|
|
||||||
use app\adminapi\lists\BaseAdminDataLists;
|
use app\adminapi\lists\BaseAdminDataLists;
|
||||||
|
use app\adminapi\logic\stats\PersonalStatsScopeTrait;
|
||||||
use app\common\lists\ListsSearchInterface;
|
use app\common\lists\ListsSearchInterface;
|
||||||
use app\common\lists\Traits\HasDataScopeFilter;
|
use app\common\lists\Traits\HasDataScopeFilter;
|
||||||
use app\common\model\stats\PersonalYeji;
|
use app\common\model\stats\PersonalYeji;
|
||||||
@@ -12,6 +13,7 @@ use app\common\model\stats\PersonalYeji;
|
|||||||
class PersonalYejiLists extends BaseAdminDataLists implements ListsSearchInterface
|
class PersonalYejiLists extends BaseAdminDataLists implements ListsSearchInterface
|
||||||
{
|
{
|
||||||
use HasDataScopeFilter;
|
use HasDataScopeFilter;
|
||||||
|
use PersonalStatsScopeTrait;
|
||||||
|
|
||||||
public function setSearch(): array
|
public function setSearch(): array
|
||||||
{
|
{
|
||||||
@@ -23,7 +25,15 @@ class PersonalYejiLists extends BaseAdminDataLists implements ListsSearchInterfa
|
|||||||
private function baseQuery()
|
private function baseQuery()
|
||||||
{
|
{
|
||||||
$query = PersonalYeji::where($this->searchWhere);
|
$query = PersonalYeji::where($this->searchWhere);
|
||||||
$this->applyDataScopeByOwner($query, 'creator_id');
|
$visibleIds = $this->getDataScopeVisibleAdminIds();
|
||||||
|
$deptId = (int) ($this->params['dept_id'] ?? 0);
|
||||||
|
|
||||||
|
$finalIds = self::intersectVisibleByDept($visibleIds, $deptId);
|
||||||
|
if ($finalIds === []) {
|
||||||
|
$query->whereRaw('0 = 1');
|
||||||
|
} elseif ($finalIds !== null) {
|
||||||
|
$query->whereIn('creator_id', $finalIds);
|
||||||
|
}
|
||||||
|
|
||||||
if (!empty($this->params['start_date']) && !empty($this->params['end_date'])) {
|
if (!empty($this->params['start_date']) && !empty($this->params['end_date'])) {
|
||||||
$query->whereBetween('yeji_date', [$this->params['start_date'], $this->params['end_date']]);
|
$query->whereBetween('yeji_date', [$this->params['start_date'], $this->params['end_date']]);
|
||||||
@@ -34,7 +44,7 @@ class PersonalYejiLists extends BaseAdminDataLists implements ListsSearchInterfa
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($this->params['media_source'])) {
|
if (!empty($this->params['media_source'])) {
|
||||||
$query->whereLike('media_source', '%' . trim((string) $this->params['media_source']) . '%');
|
$query->where('media_source', trim((string) $this->params['media_source']));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($this->params['creator_id'])) {
|
if (!empty($this->params['creator_id'])) {
|
||||||
@@ -46,11 +56,13 @@ class PersonalYejiLists extends BaseAdminDataLists implements ListsSearchInterfa
|
|||||||
|
|
||||||
public function lists(): array
|
public function lists(): array
|
||||||
{
|
{
|
||||||
return $this->baseQuery()
|
$rows = $this->baseQuery()
|
||||||
->order(['yeji_date' => 'desc', 'id' => 'desc'])
|
->order(['yeji_date' => 'desc', 'id' => 'desc'])
|
||||||
->limit($this->limitOffset, $this->limitLength)
|
->limit($this->limitOffset, $this->limitLength)
|
||||||
->select()
|
->select()
|
||||||
->toArray();
|
->toArray();
|
||||||
|
|
||||||
|
return self::attachDeptInfoToRows($rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function count(): int
|
public function count(): int
|
||||||
|
|||||||
@@ -64,12 +64,6 @@ class PersonalAccountCostLogic extends BaseLogic
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self::canMutateRecord($adminId, $adminInfo, (int) $model->creator_id)) {
|
|
||||||
self::setError('仅可编辑本人录入的账户消耗');
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$model->amount = round((float) ($params['amount'] ?? 0), 2);
|
$model->amount = round((float) ($params['amount'] ?? 0), 2);
|
||||||
$model->remark = (string) ($params['remark'] ?? '');
|
$model->remark = (string) ($params['remark'] ?? '');
|
||||||
$model->updater_id = $adminId;
|
$model->updater_id = $adminId;
|
||||||
@@ -100,12 +94,6 @@ class PersonalAccountCostLogic extends BaseLogic
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self::canMutateRecord($adminId, $adminInfo, (int) $model->creator_id)) {
|
|
||||||
self::setError('仅可删除本人录入的账户消耗');
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$model->delete();
|
$model->delete();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace app\adminapi\logic\stats;
|
namespace app\adminapi\logic\stats;
|
||||||
|
|
||||||
|
use app\adminapi\logic\dept\DeptLogic;
|
||||||
use app\common\model\auth\AdminDept;
|
use app\common\model\auth\AdminDept;
|
||||||
|
use app\common\model\dept\Dept;
|
||||||
use app\common\model\stats\PersonalAccountCost;
|
use app\common\model\stats\PersonalAccountCost;
|
||||||
use app\common\model\stats\PersonalYeji;
|
use app\common\model\stats\PersonalYeji;
|
||||||
use app\common\service\DataScope\DataScopeService;
|
use app\common\service\DataScope\DataScopeService;
|
||||||
|
use think\facade\Config;
|
||||||
|
|
||||||
trait PersonalStatsScopeTrait
|
trait PersonalStatsScopeTrait
|
||||||
{
|
{
|
||||||
@@ -21,26 +24,124 @@ trait PersonalStatsScopeTrait
|
|||||||
return (int) ($deptId ?: 0);
|
return (int) ($deptId ?: 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<int, int> $creatorIds
|
||||||
|
* @return array{0: array<int, int>, 1: array<int, string>}
|
||||||
|
*/
|
||||||
|
protected static function loadAdminDeptMap(array $creatorIds): array
|
||||||
|
{
|
||||||
|
$creatorIds = array_values(array_unique(array_filter(array_map('intval', $creatorIds))));
|
||||||
|
if ($creatorIds === []) {
|
||||||
|
return [[], []];
|
||||||
|
}
|
||||||
|
$rows = AdminDept::whereIn('admin_id', $creatorIds)
|
||||||
|
->field('admin_id, dept_id')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
$adminToDeptId = [];
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$adminId = (int) ($row['admin_id'] ?? 0);
|
||||||
|
$deptId = (int) ($row['dept_id'] ?? 0);
|
||||||
|
if ($adminId <= 0 || $deptId <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!isset($adminToDeptId[$adminId])) {
|
||||||
|
$adminToDeptId[$adminId] = $deptId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$deptNameMap = [];
|
||||||
|
$deptIds = array_values(array_unique($adminToDeptId));
|
||||||
|
if ($deptIds !== []) {
|
||||||
|
$deptNameMap = Dept::whereIn('id', $deptIds)
|
||||||
|
->column('name', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$adminToDeptId, $deptNameMap];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<int, array<string, mixed>> $rows
|
||||||
|
* @return array<int, array<string, mixed>>
|
||||||
|
*/
|
||||||
|
protected static function attachDeptInfoToRows(array $rows): array
|
||||||
|
{
|
||||||
|
if ($rows === []) {
|
||||||
|
return $rows;
|
||||||
|
}
|
||||||
|
$creatorIds = array_map(static fn (array $row): int => (int) ($row['creator_id'] ?? 0), $rows);
|
||||||
|
[$adminToDeptId, $deptNameMap] = self::loadAdminDeptMap($creatorIds);
|
||||||
|
foreach ($rows as &$row) {
|
||||||
|
$creatorId = (int) ($row['creator_id'] ?? 0);
|
||||||
|
$deptId = $adminToDeptId[$creatorId] ?? 0;
|
||||||
|
$row['dept_id'] = $deptId;
|
||||||
|
$row['dept_name'] = $deptId > 0 ? (string) ($deptNameMap[$deptId] ?? '') : '';
|
||||||
|
}
|
||||||
|
unset($row);
|
||||||
|
|
||||||
|
return $rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 dept_id(包含其子部门)收窄可见 admin id 集合。
|
||||||
|
* 与 visibleAdminIds 取交集。
|
||||||
|
*
|
||||||
|
* @param array<int>|null $visibleAdminIds null 表示不限
|
||||||
|
* @return array<int>|null 返回 null 表示外部条件无需附加;返回 [] 表示无可见 admin
|
||||||
|
*/
|
||||||
|
protected static function intersectVisibleByDept(?array $visibleAdminIds, int $deptId): ?array
|
||||||
|
{
|
||||||
|
if ($deptId <= 0) {
|
||||||
|
return $visibleAdminIds;
|
||||||
|
}
|
||||||
|
$deptIds = DeptLogic::getSelfAndDescendantIds($deptId);
|
||||||
|
if ($deptIds === []) {
|
||||||
|
$deptIds = [$deptId];
|
||||||
|
}
|
||||||
|
$adminIds = AdminDept::whereIn('dept_id', $deptIds)->column('admin_id');
|
||||||
|
$adminIds = array_values(array_unique(array_filter(array_map('intval', $adminIds), static fn (int $v): bool => $v > 0)));
|
||||||
|
|
||||||
|
if ($visibleAdminIds === null) {
|
||||||
|
return $adminIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_values(array_intersect($visibleAdminIds, $adminIds));
|
||||||
|
}
|
||||||
|
|
||||||
protected static function normalizeMediaSource(string $mediaSource): string
|
protected static function normalizeMediaSource(string $mediaSource): string
|
||||||
{
|
{
|
||||||
return trim($mediaSource);
|
return trim($mediaSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<int>|null
|
* 与 project.self_input_stats_view_all_roles 一致:超管或白名单角色可见全部录入人数据。
|
||||||
*/
|
*/
|
||||||
protected static function getVisibleCreatorIds(int $adminId, array $adminInfo): ?array
|
protected static function canViewAllSelfInputStats(array $adminInfo): bool
|
||||||
{
|
|
||||||
return DataScopeService::getVisibleAdminIds($adminId, $adminInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function canMutateRecord(int $adminId, array $adminInfo, int $creatorId): bool
|
|
||||||
{
|
{
|
||||||
if ((int) ($adminInfo['root'] ?? 0) === 1) {
|
if ((int) ($adminInfo['root'] ?? 0) === 1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
$allow = Config::get('project.self_input_stats_view_all_roles', []);
|
||||||
|
$allow = array_map('intval', is_array($allow) ? $allow : []);
|
||||||
|
if ($allow === []) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$myRoles = array_map('intval', $adminInfo['role_id'] ?? []);
|
||||||
|
|
||||||
return $adminId > 0 && $adminId === $creatorId;
|
return count(array_intersect($myRoles, $allow)) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int>|null null=全部录入人;[]=无可见;int[]=可见 creator_id 集合
|
||||||
|
*/
|
||||||
|
protected static function getVisibleCreatorIds(int $adminId, array $adminInfo): ?array
|
||||||
|
{
|
||||||
|
if (self::canViewAllSelfInputStats($adminInfo)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DataScopeService::getVisibleAdminIds($adminId, $adminInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function assertRecordVisible(int $adminId, array $adminInfo, int $creatorId): bool
|
protected static function assertRecordVisible(int $adminId, array $adminInfo, int $creatorId): bool
|
||||||
|
|||||||
@@ -71,12 +71,6 @@ class PersonalYejiLogic extends BaseLogic
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self::canMutateRecord($adminId, $adminInfo, (int) $model->creator_id)) {
|
|
||||||
self::setError('仅可编辑本人录入的业绩');
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$model->add_fans_count = (int) ($params['add_fans_count'] ?? 0);
|
$model->add_fans_count = (int) ($params['add_fans_count'] ?? 0);
|
||||||
$model->total_open_count = (int) ($params['total_open_count'] ?? 0);
|
$model->total_open_count = (int) ($params['total_open_count'] ?? 0);
|
||||||
$model->unreplied_count = (int) ($params['unreplied_count'] ?? 0);
|
$model->unreplied_count = (int) ($params['unreplied_count'] ?? 0);
|
||||||
@@ -114,12 +108,6 @@ class PersonalYejiLogic extends BaseLogic
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self::canMutateRecord($adminId, $adminInfo, (int) $model->creator_id)) {
|
|
||||||
self::setError('仅可删除本人录入的业绩');
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$model->delete();
|
$model->delete();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -18,10 +18,13 @@ class SelfInputLogic extends BaseLogic
|
|||||||
$pageNo = max(1, (int) ($params['page_no'] ?? 1));
|
$pageNo = max(1, (int) ($params['page_no'] ?? 1));
|
||||||
$pageSize = min(100, max(1, (int) ($params['page_size'] ?? 15)));
|
$pageSize = min(100, max(1, (int) ($params['page_size'] ?? 15)));
|
||||||
$mediaSource = trim((string) ($params['media_source'] ?? ''));
|
$mediaSource = trim((string) ($params['media_source'] ?? ''));
|
||||||
|
$deptId = (int) ($params['dept_id'] ?? 0);
|
||||||
|
|
||||||
$yejiQuery = self::buildYejiQuery($startDate, $endDate, $adminId, $adminInfo);
|
$effectiveAdminIds = self::resolveEffectiveAdminIds($adminId, $adminInfo, $deptId);
|
||||||
|
|
||||||
|
$yejiQuery = self::buildYejiQuery($startDate, $endDate, $effectiveAdminIds);
|
||||||
if ($mediaSource !== '') {
|
if ($mediaSource !== '') {
|
||||||
$yejiQuery->whereLike('media_source', '%' . $mediaSource . '%');
|
$yejiQuery->where('media_source', $mediaSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
$count = (int) (clone $yejiQuery)->count();
|
$count = (int) (clone $yejiQuery)->count();
|
||||||
@@ -31,7 +34,7 @@ class SelfInputLogic extends BaseLogic
|
|||||||
->select()
|
->select()
|
||||||
->toArray();
|
->toArray();
|
||||||
|
|
||||||
$costMap = self::loadAccountCostMap($startDate, $endDate, $adminId, $adminInfo, $mediaSource);
|
$costMap = self::loadAccountCostMap($startDate, $endDate, $effectiveAdminIds, $mediaSource);
|
||||||
|
|
||||||
$lists = [];
|
$lists = [];
|
||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
@@ -44,10 +47,11 @@ class SelfInputLogic extends BaseLogic
|
|||||||
$entity['account_cost'] = round((float) ($costMap[$costKey] ?? 0), 2);
|
$entity['account_cost'] = round((float) ($costMap[$costKey] ?? 0), 2);
|
||||||
$lists[] = self::finalizeMetrics($entity);
|
$lists[] = self::finalizeMetrics($entity);
|
||||||
}
|
}
|
||||||
|
$lists = self::attachDeptInfoToRows($lists);
|
||||||
|
|
||||||
$allYejiRows = self::buildYejiQuery($startDate, $endDate, $adminId, $adminInfo);
|
$allYejiRows = self::buildYejiQuery($startDate, $endDate, $effectiveAdminIds);
|
||||||
if ($mediaSource !== '') {
|
if ($mediaSource !== '') {
|
||||||
$allYejiRows->whereLike('media_source', '%' . $mediaSource . '%');
|
$allYejiRows->where('media_source', $mediaSource);
|
||||||
}
|
}
|
||||||
$allYeji = $allYejiRows->select()->toArray();
|
$allYeji = $allYejiRows->select()->toArray();
|
||||||
|
|
||||||
@@ -85,39 +89,83 @@ class SelfInputLogic extends BaseLogic
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function buildYejiQuery(string $startDate, string $endDate, int $adminId, array $adminInfo)
|
/**
|
||||||
|
* 从已录入的业绩/账户消耗中提取去重后的自媒体来源(与列表数据权限一致)。
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public static function mediaSourceOptions(int $adminId, array $adminInfo): array
|
||||||
|
{
|
||||||
|
$effectiveAdminIds = self::resolveEffectiveAdminIds($adminId, $adminInfo, 0);
|
||||||
|
if ($effectiveAdminIds === []) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$map = [];
|
||||||
|
foreach ([PersonalYeji::class, PersonalAccountCost::class] as $modelClass) {
|
||||||
|
$query = $modelClass::where('media_source', '<>', '');
|
||||||
|
if ($effectiveAdminIds !== null) {
|
||||||
|
$query->whereIn('creator_id', $effectiveAdminIds);
|
||||||
|
}
|
||||||
|
$rows = $query->group('media_source')->column('media_source');
|
||||||
|
foreach ($rows as $raw) {
|
||||||
|
$norm = self::normalizeMediaSource((string) $raw);
|
||||||
|
if ($norm !== '') {
|
||||||
|
$map[$norm] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = array_keys($map);
|
||||||
|
sort($list, SORT_STRING);
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int>|null null = 不限;[] = 无可见
|
||||||
|
*/
|
||||||
|
private static function resolveEffectiveAdminIds(int $adminId, array $adminInfo, int $deptId): ?array
|
||||||
|
{
|
||||||
|
$visibleIds = self::getVisibleCreatorIds($adminId, $adminInfo);
|
||||||
|
|
||||||
|
return self::intersectVisibleByDept($visibleIds, $deptId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<int>|null $effectiveAdminIds
|
||||||
|
*/
|
||||||
|
private static function buildYejiQuery(string $startDate, string $endDate, ?array $effectiveAdminIds)
|
||||||
{
|
{
|
||||||
$query = PersonalYeji::whereBetween('yeji_date', [$startDate, $endDate]);
|
$query = PersonalYeji::whereBetween('yeji_date', [$startDate, $endDate]);
|
||||||
$visibleIds = self::getVisibleCreatorIds($adminId, $adminInfo);
|
if ($effectiveAdminIds === []) {
|
||||||
if ($visibleIds === []) {
|
|
||||||
$query->whereRaw('0 = 1');
|
$query->whereRaw('0 = 1');
|
||||||
} elseif ($visibleIds !== null) {
|
} elseif ($effectiveAdminIds !== null) {
|
||||||
$query->whereIn('creator_id', $visibleIds);
|
$query->whereIn('creator_id', $effectiveAdminIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param array<int>|null $effectiveAdminIds
|
||||||
* @return array<string, float>
|
* @return array<string, float>
|
||||||
*/
|
*/
|
||||||
private static function loadAccountCostMap(
|
private static function loadAccountCostMap(
|
||||||
string $startDate,
|
string $startDate,
|
||||||
string $endDate,
|
string $endDate,
|
||||||
int $adminId,
|
?array $effectiveAdminIds,
|
||||||
array $adminInfo,
|
|
||||||
string $mediaSource
|
string $mediaSource
|
||||||
): array {
|
): array {
|
||||||
$query = PersonalAccountCost::whereBetween('cost_date', [$startDate, $endDate]);
|
$query = PersonalAccountCost::whereBetween('cost_date', [$startDate, $endDate]);
|
||||||
$visibleIds = self::getVisibleCreatorIds($adminId, $adminInfo);
|
if ($effectiveAdminIds === []) {
|
||||||
if ($visibleIds === []) {
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
if ($visibleIds !== null) {
|
if ($effectiveAdminIds !== null) {
|
||||||
$query->whereIn('creator_id', $visibleIds);
|
$query->whereIn('creator_id', $effectiveAdminIds);
|
||||||
}
|
}
|
||||||
if ($mediaSource !== '') {
|
if ($mediaSource !== '') {
|
||||||
$query->whereLike('media_source', '%' . $mediaSource . '%');
|
$query->where('media_source', $mediaSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
$rows = $query
|
$rows = $query
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ class PersonalAccountCost extends BaseModel
|
|||||||
|
|
||||||
protected $deleteTime = 'delete_time';
|
protected $deleteTime = 'delete_time';
|
||||||
|
|
||||||
protected $defaultSoftDelete = 0;
|
|
||||||
|
|
||||||
protected $autoWriteTimestamp = true;
|
protected $autoWriteTimestamp = true;
|
||||||
|
|
||||||
protected $createTime = 'create_time';
|
protected $createTime = 'create_time';
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ class PersonalYeji extends BaseModel
|
|||||||
|
|
||||||
protected $deleteTime = 'delete_time';
|
protected $deleteTime = 'delete_time';
|
||||||
|
|
||||||
protected $defaultSoftDelete = 0;
|
|
||||||
|
|
||||||
protected $autoWriteTimestamp = true;
|
protected $autoWriteTimestamp = true;
|
||||||
|
|
||||||
protected $createTime = 'create_time';
|
protected $createTime = 'create_time';
|
||||||
|
|||||||
@@ -123,6 +123,11 @@ return [
|
|||||||
// 订单管理列表(order/index):以下角色 ID + root 可查看全部订单,其余仅本人创建
|
// 订单管理列表(order/index):以下角色 ID + root 可查看全部订单,其余仅本人创建
|
||||||
'order_list_view_all_roles' => [0, 3, 4, 9, 6],
|
'order_list_view_all_roles' => [0, 3, 4, 9, 6],
|
||||||
|
|
||||||
|
// 自录转化统计(stats.self_input / personal_yeji / personal_account_cost):
|
||||||
|
// 以下角色 ID + root 在列表与总览中可见全部录入人的业绩/账户消耗(不受角色 data_scope 收窄)。
|
||||||
|
// 编辑/删除由菜单按钮权限(stats.personal_yeji/edit 等)控制,不在此配置。
|
||||||
|
'self_input_stats_view_all_roles' => [0, 3, 4, 9, 6],
|
||||||
|
|
||||||
// 业务订单列表金额统计:医助角色 ID;非支付审核白名单的医助仅统计其诊单 assistant_id=本人 的业绩
|
// 业务订单列表金额统计:医助角色 ID;非支付审核白名单的医助仅统计其诊单 assistant_id=本人 的业绩
|
||||||
'prescription_order_stats_assistant_role_id' => 2,
|
'prescription_order_stats_assistant_role_id' => 2,
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
-- 自录转化统计菜单(挂在「数据统计」目录下)
|
-- 自录数据统计菜单(挂在「数据统计」目录下)
|
||||||
-- 主页面: /stats/self_input
|
-- 目录: /stats/self_input(自录数据统计)
|
||||||
-- 账户消耗: /stats/self_input/account_cost
|
-- 子菜单:
|
||||||
|
-- 自录转化统计 -> /stats/self_input
|
||||||
|
-- 账户消耗录入 -> /stats/self_input/account_cost
|
||||||
|
-- 子菜单 paths 为相对父级目录的路径片段。
|
||||||
|
|
||||||
|
-- ========== 已执行旧版 SQL 的环境:迁移到「自录数据统计」目录 ==========
|
||||||
SET @stats_root_id = (
|
SET @stats_root_id = (
|
||||||
SELECT `id` FROM `zyt_system_menu`
|
SELECT `id` FROM `zyt_system_menu`
|
||||||
WHERE `paths` = '/stats' AND `type` = 'M'
|
WHERE `paths` = '/stats' AND `type` = 'M'
|
||||||
@@ -12,9 +16,69 @@ SET @stats_root_id = (
|
|||||||
INSERT INTO `zyt_system_menu`
|
INSERT INTO `zyt_system_menu`
|
||||||
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
|
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
|
||||||
SELECT
|
SELECT
|
||||||
@stats_root_id, 'C', '自录转化统计', '', 5, 'stats.self_input/overview', '/stats/self_input', '/stats/self_input/index', '', '', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
|
@stats_root_id, 'M', '自录数据统计', '', 5, '', 'self_input', '', '', '', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
|
||||||
FROM DUAL
|
FROM DUAL
|
||||||
WHERE @stats_root_id IS NOT NULL
|
WHERE @stats_root_id IS NOT NULL
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM `zyt_system_menu`
|
||||||
|
WHERE `pid` = @stats_root_id AND `type` = 'M' AND `name` = '自录数据统计'
|
||||||
|
);
|
||||||
|
|
||||||
|
SET @self_input_group_id = (
|
||||||
|
SELECT `id` FROM `zyt_system_menu`
|
||||||
|
WHERE `pid` = @stats_root_id AND `type` = 'M' AND `name` = '自录数据统计'
|
||||||
|
ORDER BY `id` ASC
|
||||||
|
LIMIT 1
|
||||||
|
);
|
||||||
|
|
||||||
|
UPDATE `zyt_system_menu`
|
||||||
|
SET `pid` = @self_input_group_id,
|
||||||
|
`paths` = '',
|
||||||
|
`component` = 'stats/self_input/index',
|
||||||
|
`sort` = 1
|
||||||
|
WHERE `perms` = 'stats.self_input/overview'
|
||||||
|
AND @self_input_group_id IS NOT NULL;
|
||||||
|
|
||||||
|
UPDATE `zyt_system_menu`
|
||||||
|
SET `pid` = @self_input_group_id,
|
||||||
|
`paths` = 'account_cost',
|
||||||
|
`component` = 'stats/self_input/account_cost',
|
||||||
|
`sort` = 2
|
||||||
|
WHERE `perms` = 'stats.personal_account_cost/lists'
|
||||||
|
AND @self_input_group_id IS NOT NULL;
|
||||||
|
|
||||||
|
-- ========== 全新安装:目录 + 子菜单 + 按钮权限 ==========
|
||||||
|
SET @stats_root_id = (
|
||||||
|
SELECT `id` FROM `zyt_system_menu`
|
||||||
|
WHERE `paths` = '/stats' AND `type` = 'M'
|
||||||
|
ORDER BY `id` ASC
|
||||||
|
LIMIT 1
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO `zyt_system_menu`
|
||||||
|
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
|
||||||
|
SELECT
|
||||||
|
@stats_root_id, 'M', '自录数据统计', '', 5, '', 'self_input', '', '', '', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
|
||||||
|
FROM DUAL
|
||||||
|
WHERE @stats_root_id IS NOT NULL
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM `zyt_system_menu`
|
||||||
|
WHERE `pid` = @stats_root_id AND `type` = 'M' AND `name` = '自录数据统计'
|
||||||
|
);
|
||||||
|
|
||||||
|
SET @self_input_group_id = (
|
||||||
|
SELECT `id` FROM `zyt_system_menu`
|
||||||
|
WHERE `pid` = @stats_root_id AND `type` = 'M' AND `name` = '自录数据统计'
|
||||||
|
ORDER BY `id` ASC
|
||||||
|
LIMIT 1
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO `zyt_system_menu`
|
||||||
|
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
|
||||||
|
SELECT
|
||||||
|
@self_input_group_id, 'C', '自录转化统计', '', 1, 'stats.self_input/overview', '', 'stats/self_input/index', '', '', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
|
||||||
|
FROM DUAL
|
||||||
|
WHERE @self_input_group_id IS NOT NULL
|
||||||
AND NOT EXISTS (
|
AND NOT EXISTS (
|
||||||
SELECT 1 FROM `zyt_system_menu`
|
SELECT 1 FROM `zyt_system_menu`
|
||||||
WHERE `perms` = 'stats.self_input/overview'
|
WHERE `perms` = 'stats.self_input/overview'
|
||||||
@@ -49,9 +113,9 @@ FROM DUAL WHERE @self_input_menu_id IS NOT NULL AND NOT EXISTS (SELECT 1 FROM `z
|
|||||||
INSERT INTO `zyt_system_menu`
|
INSERT INTO `zyt_system_menu`
|
||||||
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
|
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
|
||||||
SELECT
|
SELECT
|
||||||
@stats_root_id, 'C', '账户消耗录入', '', 6, 'stats.personal_account_cost/lists', '/stats/self_input/account_cost', '/stats/self_input/account_cost', '', '', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
|
@self_input_group_id, 'C', '账户消耗录入', '', 2, 'stats.personal_account_cost/lists', 'account_cost', 'stats/self_input/account_cost', '', '', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
|
||||||
FROM DUAL
|
FROM DUAL
|
||||||
WHERE @stats_root_id IS NOT NULL
|
WHERE @self_input_group_id IS NOT NULL
|
||||||
AND NOT EXISTS (
|
AND NOT EXISTS (
|
||||||
SELECT 1 FROM `zyt_system_menu`
|
SELECT 1 FROM `zyt_system_menu`
|
||||||
WHERE `perms` = 'stats.personal_account_cost/lists'
|
WHERE `perms` = 'stats.personal_account_cost/lists'
|
||||||
@@ -77,3 +141,5 @@ INSERT INTO `zyt_system_menu`
|
|||||||
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
|
(`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_show`, `is_disable`, `create_time`, `update_time`)
|
||||||
SELECT @personal_cost_menu_id, 'A', '删除消耗', '', 3, 'stats.personal_account_cost/delete', '', '', '', '', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
|
SELECT @personal_cost_menu_id, 'A', '删除消耗', '', 3, 'stats.personal_account_cost/delete', '', '', '', '', 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
|
||||||
FROM DUAL WHERE @personal_cost_menu_id IS NOT NULL AND NOT EXISTS (SELECT 1 FROM `zyt_system_menu` WHERE `perms` = 'stats.personal_account_cost/delete');
|
FROM DUAL WHERE @personal_cost_menu_id IS NOT NULL AND NOT EXISTS (SELECT 1 FROM `zyt_system_menu` WHERE `perms` = 'stats.personal_account_cost/delete');
|
||||||
|
|
||||||
|
-- 角色需勾选新目录「自录数据统计」后,子菜单权限才会一并生效(与 likeadmin 菜单树授权一致)
|
||||||
|
|||||||
Reference in New Issue
Block a user