Compare commits
3
Commits
8f67f27b36
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afd729b1ac | ||
|
|
5035879651 | ||
|
|
c61fafeb01 |
+3
-3
@@ -3,9 +3,9 @@ FROM node:22-alpine
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy package descriptors and install dependencies
|
# Copy package descriptors and npm configuration
|
||||||
COPY package*.json ./
|
COPY package*.json .npmrc* ./
|
||||||
RUN npm ci
|
RUN npm ci --registry=https://registry.npmmirror.com
|
||||||
|
|
||||||
# Copy application source code
|
# Copy application source code
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// /src/api/professorApi.js
|
||||||
|
import axiosInstance from './axiosInstance'
|
||||||
|
|
||||||
|
export const professorApi = {
|
||||||
|
getPortal: () => axiosInstance.get('/professors/portal')
|
||||||
|
}
|
||||||
@@ -12,6 +12,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<nav>
|
<nav>
|
||||||
<RouterLink :to="{ name: 'account' }" class="nav-link">خلاصه</RouterLink>
|
<RouterLink :to="{ name: 'account' }" class="nav-link">خلاصه</RouterLink>
|
||||||
|
<RouterLink v-if="auth.isProfessor" :to="{ name: 'professor-portal' }" class="nav-link professor-link">
|
||||||
|
<span class="professor-icon">🎓</span>
|
||||||
|
میزکار تدریس و اساتید
|
||||||
|
</RouterLink>
|
||||||
<RouterLink :to="{ name: 'my-classes' }" class="nav-link">کلاسهای من</RouterLink>
|
<RouterLink :to="{ name: 'my-classes' }" class="nav-link">کلاسهای من</RouterLink>
|
||||||
<RouterLink :to="{ name: 'my-certificates' }" class="nav-link">گواهینامهها</RouterLink>
|
<RouterLink :to="{ name: 'my-certificates' }" class="nav-link">گواهینامهها</RouterLink>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -121,6 +125,26 @@ nav {
|
|||||||
color: var(--leaf);
|
color: var(--leaf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.professor-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
background: rgba(232, 163, 23, 0.08);
|
||||||
|
border: 1px solid rgba(232, 163, 23, 0.25);
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.professor-link:hover,
|
||||||
|
.professor-link.router-link-active {
|
||||||
|
background: linear-gradient(135deg, rgba(232, 163, 23, 0.2), rgba(45, 106, 79, 0.15));
|
||||||
|
color: var(--ink);
|
||||||
|
border-color: var(--saffron);
|
||||||
|
}
|
||||||
|
|
||||||
|
.professor-icon {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.logout-btn {
|
.logout-btn {
|
||||||
margin-top: 1.25rem;
|
margin-top: 1.25rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -43,6 +43,12 @@ const routes = [
|
|||||||
component: () => import('@/views/account/AccountHomeView.vue'),
|
component: () => import('@/views/account/AccountHomeView.vue'),
|
||||||
meta: { title: 'پنل کاربری | گام نو' }
|
meta: { title: 'پنل کاربری | گام نو' }
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'teaching',
|
||||||
|
name: 'professor-portal',
|
||||||
|
component: () => import('@/views/account/ProfessorPortalView.vue'),
|
||||||
|
meta: { title: 'میزکار اساتید و تدریس | گام نو' }
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'classes',
|
path: 'classes',
|
||||||
name: 'my-classes',
|
name: 'my-classes',
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ export const useAuthStore = defineStore('auth', () => {
|
|||||||
if (!user.value) return ''
|
if (!user.value) return ''
|
||||||
return `${user.value.name || ''}`.trim()
|
return `${user.value.name || ''}`.trim()
|
||||||
})
|
})
|
||||||
|
const isProfessor = computed(() => {
|
||||||
|
const roleName = user.value?.role?.name || user.value?.role
|
||||||
|
return roleName === 'Professor' || user.value?.isProfessor === true
|
||||||
|
})
|
||||||
|
|
||||||
function setTokens(access, refresh) {
|
function setTokens(access, refresh) {
|
||||||
accessToken.value = access
|
accessToken.value = access
|
||||||
@@ -71,6 +75,7 @@ export const useAuthStore = defineStore('auth', () => {
|
|||||||
user,
|
user,
|
||||||
isAuthenticated,
|
isAuthenticated,
|
||||||
fullName,
|
fullName,
|
||||||
|
isProfessor,
|
||||||
setTokens,
|
setTokens,
|
||||||
setUser,
|
setUser,
|
||||||
login,
|
login,
|
||||||
|
|||||||
@@ -5,6 +5,17 @@
|
|||||||
<p>کلاسهای ثبتشده و گواهینامههایتان را از اینجا مدیریت کنید.</p>
|
<p>کلاسهای ثبتشده و گواهینامههایتان را از اینجا مدیریت کنید.</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
<div v-if="auth.isProfessor" class="professor-banner">
|
||||||
|
<div class="professor-banner-content">
|
||||||
|
<div class="professor-badge-pill">🎓 پنل ویژه اساتید گام نو</div>
|
||||||
|
<h2>میزکار و پنل تدریس اساتید</h2>
|
||||||
|
<p>مشاهده کلاسهای در حال برگزاری، زمانبندی جلسات، آمار دانشجویان و گزارش و نمودار سهم تدریس شما</p>
|
||||||
|
</div>
|
||||||
|
<RouterLink :to="{ name: 'professor-portal' }" class="professor-cta-btn">
|
||||||
|
ورود به میزکار تدریس ←
|
||||||
|
</RouterLink>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="summary-grid">
|
<div class="summary-grid">
|
||||||
<RouterLink :to="{ name: 'my-classes' }" class="summary-tile">
|
<RouterLink :to="{ name: 'my-classes' }" class="summary-tile">
|
||||||
<span class="tile-label">کلاسهای من</span>
|
<span class="tile-label">کلاسهای من</span>
|
||||||
@@ -72,6 +83,77 @@ onMounted(async () => {
|
|||||||
color: var(--ink-soft);
|
color: var(--ink-soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.professor-banner {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 1.5rem;
|
||||||
|
padding: 1.5rem 1.75rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
border-radius: 1.25rem;
|
||||||
|
background: linear-gradient(135deg, #14352b 0%, #1f4e3f 60%, #2d6a4f 100%);
|
||||||
|
color: var(--chalk);
|
||||||
|
box-shadow: 0 10px 25px -5px rgba(20, 53, 43, 0.25);
|
||||||
|
border: 1px solid rgba(232, 163, 23, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.professor-badge-pill {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 0.2rem 0.65rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(232, 163, 23, 0.2);
|
||||||
|
color: #ffd166;
|
||||||
|
border: 1px solid rgba(232, 163, 23, 0.4);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.professor-banner h2 {
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-size: 1.35rem;
|
||||||
|
color: #fff;
|
||||||
|
margin: 0 0 0.35rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.professor-banner p {
|
||||||
|
font-size: 0.88rem;
|
||||||
|
color: rgba(255, 255, 255, 0.85);
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.5;
|
||||||
|
max-width: 540px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.professor-cta-btn {
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 0.75rem 1.25rem;
|
||||||
|
border-radius: 0.85rem;
|
||||||
|
background: var(--saffron);
|
||||||
|
color: var(--ink);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
box-shadow: 0 4px 12px rgba(232, 163, 23, 0.3);
|
||||||
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.professor-cta-btn:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 6px 16px rgba(232, 163, 23, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.professor-banner {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
.professor-cta-btn {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.summary-grid {
|
.summary-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user