feat: 权限细化、商业认证跳转、UI改进
权限: - viewer 管理配方页只显示我的配方,隐藏公共配方库和工具栏 - 高级编辑者可看到精油价目信息不全的红色提示 - 商业核算删除按钮仅管理员可见 - 搜索未收录通知只发管理员和高级编辑者 Tab 可见性: - 所有用户可见:配方查询、管理配方、个人库存、精油价目、商业核算 - 需登录的 tab 点击弹登录框,登录后跳转 - 操作日志/Bug/用户管理仅管理员可见 商业核算: - 未认证用户可看项目列表,点详情提示去认证 - 跳转到我的账户页商业认证区域并自动滚动 其他: - 我的配方和收藏配方默认折叠 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -241,7 +241,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Business Verification -->
|
||||
<div v-if="!auth.isBusiness" class="section-card">
|
||||
<div v-if="!auth.isBusiness" ref="bizCertRef" class="section-card">
|
||||
<h4>💼 商业认证</h4>
|
||||
<p class="hint-text">申请商业认证后可使用商业核算功能。</p>
|
||||
<div class="form-group">
|
||||
@@ -259,8 +259,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ref, nextTick, onMounted, watch } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useAuthStore } from '../stores/auth'
|
||||
import { useOilsStore } from '../stores/oils'
|
||||
import { useDiaryStore } from '../stores/diary'
|
||||
@@ -274,8 +274,10 @@ const oils = useOilsStore()
|
||||
const diaryStore = useDiaryStore()
|
||||
const ui = useUiStore()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const bizCertRef = ref(null)
|
||||
|
||||
const activeTab = ref('brand')
|
||||
const activeTab = ref(route.query.tab || 'brand')
|
||||
const pasteText = ref('')
|
||||
const selectedDiaryId = ref(null)
|
||||
const returnRecipeId = ref(null)
|
||||
@@ -305,6 +307,11 @@ onMounted(async () => {
|
||||
displayName.value = auth.user.display_name || ''
|
||||
await loadBrandSettings()
|
||||
returnRecipeId.value = localStorage.getItem('oil_return_recipe_id') || null
|
||||
// 从商业核算跳转过来,滚到商业认证区域
|
||||
if (route.query.section === 'biz-cert') {
|
||||
await nextTick()
|
||||
bizCertRef.value?.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
||||
}
|
||||
})
|
||||
|
||||
function goBackToRecipe() {
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
v-for="name in filteredOilNames"
|
||||
:key="name + '-' + cardVersion"
|
||||
class="oil-chip"
|
||||
:class="{ 'oil-chip--inactive': getMeta(name)?.isActive === false, 'oil-chip--incomplete': auth.isAdmin && isIncomplete(name) }"
|
||||
:class="{ 'oil-chip--inactive': getMeta(name)?.isActive === false, 'oil-chip--incomplete': auth.canManage && isIncomplete(name) }"
|
||||
:style="chipStyle(name)"
|
||||
@click="openOilDetail(name)"
|
||||
>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<!-- Project List -->
|
||||
<div class="toolbar">
|
||||
<h3 class="page-title">💼 商业核算</h3>
|
||||
<button class="btn-primary" @click="createProject">+ 新建项目</button>
|
||||
<button v-if="auth.isBusiness" class="btn-primary" @click="createProject">+ 新建项目</button>
|
||||
</div>
|
||||
|
||||
<div v-if="!selectedProject" class="project-list">
|
||||
@@ -23,7 +23,7 @@
|
||||
成本 {{ oils.fmtPrice(oils.calcCost(p.ingredients)) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="proj-actions" @click.stop>
|
||||
<div v-if="auth.isAdmin" class="proj-actions" @click.stop>
|
||||
<button class="btn-icon-sm" @click="deleteProject(p)" title="删除">🗑️</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -177,6 +177,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useAuthStore } from '../stores/auth'
|
||||
import { useOilsStore } from '../stores/oils'
|
||||
import { useRecipesStore } from '../stores/recipes'
|
||||
@@ -188,6 +189,14 @@ const auth = useAuthStore()
|
||||
const oils = useOilsStore()
|
||||
const recipeStore = useRecipesStore()
|
||||
const ui = useUiStore()
|
||||
const router = useRouter()
|
||||
|
||||
async function showCertPrompt() {
|
||||
const ok = await showConfirm('此功能需要商业认证,是否前往申请认证?', { okText: '去认证', cancelText: '取消' })
|
||||
if (ok) {
|
||||
router.push('/mydiary?tab=account§ion=biz-cert')
|
||||
}
|
||||
}
|
||||
|
||||
const projects = ref([])
|
||||
const selectedProject = ref(null)
|
||||
@@ -237,6 +246,10 @@ async function createProject() {
|
||||
}
|
||||
|
||||
function selectProject(p) {
|
||||
if (!auth.isBusiness) {
|
||||
showCertPrompt()
|
||||
return
|
||||
}
|
||||
selectedProject.value = {
|
||||
...p,
|
||||
ingredients: (p.ingredients || []).map(i => ({ ...i })),
|
||||
|
||||
@@ -189,8 +189,8 @@ const selectedCategory = ref(null)
|
||||
const categories = ref([])
|
||||
const selectedRecipeIndex = ref(null)
|
||||
const selectedDiaryRecipe = ref(null)
|
||||
const showMyRecipes = ref(true)
|
||||
const showFavorites = ref(true)
|
||||
const showMyRecipes = ref(false)
|
||||
const showFavorites = ref(false)
|
||||
const catIdx = ref(0)
|
||||
const sharedCount = ref(0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user