fix: 完善打包历史与登录提示
This commit is contained in:
parent
c209ae423c
commit
3e3e4123d0
@ -45,7 +45,6 @@
|
|||||||
<input v-model="loginForm.password" type="password" placeholder="请输入密码" @keyup.enter="login">
|
<input v-model="loginForm.password" type="password" placeholder="请输入密码" @keyup.enter="login">
|
||||||
</div>
|
</div>
|
||||||
<button class="login-btn" @click="login">登录</button>
|
<button class="login-btn" @click="login">登录</button>
|
||||||
<div class="login-hint">默认账号: admin / admin123</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -153,5 +152,4 @@ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; b
|
|||||||
.form-group input:focus { outline: none; border-color: #1890ff; }
|
.form-group input:focus { outline: none; border-color: #1890ff; }
|
||||||
.login-btn { width: 100%; padding: 12px; background: #1890ff; color: white; border: none; border-radius: 6px; font-size: 16px; cursor: pointer; margin-top: 8px; }
|
.login-btn { width: 100%; padding: 12px; background: #1890ff; color: white; border: none; border-radius: 6px; font-size: 16px; cursor: pointer; margin-top: 8px; }
|
||||||
.login-btn:hover { background: #40a9ff; }
|
.login-btn:hover { background: #40a9ff; }
|
||||||
.login-hint { text-align: center; margin-top: 16px; font-size: 12px; color: #999; }
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -65,6 +65,17 @@ describe('App.vue', () => {
|
|||||||
expect(wrapper.find('.login-modal').exists()).toBe(true)
|
expect(wrapper.find('.login-modal').exists()).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('登录框不展示默认管理员账号密码', async () => {
|
||||||
|
const router = createMockRouter()
|
||||||
|
const wrapper = mount(App, {
|
||||||
|
global: { plugins: [router] },
|
||||||
|
})
|
||||||
|
await wrapper.find('.btn-login').trigger('click')
|
||||||
|
|
||||||
|
expect(wrapper.find('.login-modal').text()).not.toContain('默认账号')
|
||||||
|
expect(wrapper.find('.login-modal').text()).not.toContain('admin123')
|
||||||
|
})
|
||||||
|
|
||||||
it('登录成功后更新状态', async () => {
|
it('登录成功后更新状态', async () => {
|
||||||
fetch.mockResolvedValueOnce({
|
fetch.mockResolvedValueOnce({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|||||||
@ -8,7 +8,7 @@ window.open = vi.fn()
|
|||||||
|
|
||||||
const mockTasks = [
|
const mockTasks = [
|
||||||
{ id: '1', app_name: 'App1', build_type: 'Ad_Hoc', scheme_name: 'sch1', status: 'completed', created_at: '2024-01-01T10:00:00', dsym_path: '/path/dsym', oss_url: 'https://oss.com/app1.ipa', qr_code_path: '/path/qr.png' },
|
{ id: '1', app_name: 'App1', build_type: 'Ad_Hoc', scheme_name: 'sch1', status: 'completed', created_at: '2024-01-01T10:00:00', dsym_path: '/path/dsym', oss_url: 'https://oss.com/app1.ipa', qr_code_path: '/path/qr.png' },
|
||||||
{ id: '2', app_name: 'App2', build_type: 'App_Store', scheme_name: 'sch2', status: 'failed', created_at: '2024-01-02T10:00:00', error_message: '构建失败' },
|
{ id: '2', app_name: 'App2', build_type: 'App_Store', scheme_name: 'sch2', status: 'failed', created_at: '2024-01-02T10:00:00', error_message: '构建失败', error_category: 'compilation' },
|
||||||
{ id: '3', app_name: 'App3', build_type: 'Ad_Hoc', scheme_name: 'sch1', status: 'pending', created_at: '2024-01-03T10:00:00' },
|
{ id: '3', app_name: 'App3', build_type: 'Ad_Hoc', scheme_name: 'sch1', status: 'pending', created_at: '2024-01-03T10:00:00' },
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ describe('HistoryView.vue', () => {
|
|||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
const rows = wrapper.findAll('tbody tr')
|
const rows = wrapper.findAll('tbody tr')
|
||||||
expect(rows.length).toBe(2) // App2(failed) 默认隐藏
|
expect(rows.length).toBe(3)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('显示任务信息', async () => {
|
it('显示任务信息', async () => {
|
||||||
@ -58,23 +58,23 @@ describe('HistoryView.vue', () => {
|
|||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
expect(wrapper.text()).toContain('App1')
|
expect(wrapper.text()).toContain('App1')
|
||||||
// App2 是 failed 状态,默认隐藏
|
expect(wrapper.text()).toContain('App2')
|
||||||
expect(wrapper.text()).not.toContain('App2')
|
|
||||||
expect(wrapper.text()).toContain('Ad_Hoc')
|
expect(wrapper.text()).toContain('Ad_Hoc')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('默认隐藏失败和已取消的任务', async () => {
|
it('默认显示失败任务及完整失败原因', async () => {
|
||||||
const router = createMockRouter()
|
const router = createMockRouter()
|
||||||
const wrapper = mount(HistoryView, {
|
const wrapper = mount(HistoryView, {
|
||||||
global: { plugins: [router] },
|
global: { plugins: [router] },
|
||||||
})
|
})
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
// 只显示 App1(completed)和 App3(pending),App2(failed)被隐藏
|
|
||||||
const rows = wrapper.findAll('tbody tr')
|
const rows = wrapper.findAll('tbody tr')
|
||||||
expect(rows.length).toBe(2)
|
expect(rows.length).toBe(3)
|
||||||
expect(wrapper.text()).toContain('App1')
|
expect(wrapper.text()).toContain('App1')
|
||||||
expect(wrapper.text()).toContain('App3')
|
expect(wrapper.text()).toContain('App3')
|
||||||
|
expect(wrapper.text()).toContain('失败')
|
||||||
|
expect(wrapper.text()).toContain('编译错误')
|
||||||
expect(wrapper.text()).toContain('等待中')
|
expect(wrapper.text()).toContain('等待中')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -325,7 +325,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>密码 *</label>
|
<label>密码 *</label>
|
||||||
<input v-model="userForm.password" type="password" placeholder="至少 6 位">
|
<input v-model="userForm.password" type="password" placeholder="至少 12 位">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="checkbox-label">
|
<label class="checkbox-label">
|
||||||
@ -349,7 +349,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>新密码</label>
|
<label>新密码</label>
|
||||||
<input v-model="newPassword" type="password" placeholder="至少 6 位">
|
<input v-model="newPassword" type="password" placeholder="至少 12 位">
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 20px; display: flex; gap: 12px; justify-content: flex-end;">
|
<div style="margin-top: 20px; display: flex; gap: 12px; justify-content: flex-end;">
|
||||||
<button class="action-btn" style="padding: 8px 16px;" @click="showPasswordModal = false">取消</button>
|
<button class="action-btn" style="padding: 8px 16px;" @click="showPasswordModal = false">取消</button>
|
||||||
@ -650,6 +650,10 @@ const createUser = async () => {
|
|||||||
alert('请填写用户名和密码')
|
alert('请填写用户名和密码')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (userForm.value.password.length < 12) {
|
||||||
|
alert('密码至少 12 位')
|
||||||
|
return
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const res = await authFetch('/api/users', {
|
const res = await authFetch('/api/users', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -674,8 +678,8 @@ const openPasswordModal = (u) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const changePassword = async () => {
|
const changePassword = async () => {
|
||||||
if (!newPassword.value || newPassword.value.length < 6) {
|
if (!newPassword.value || newPassword.value.length < 12) {
|
||||||
alert('密码至少 6 位')
|
alert('密码至少 12 位')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -46,7 +46,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ task.scheme_name }}</td>
|
<td>{{ task.scheme_name }}</td>
|
||||||
<td>
|
<td class="status-cell">
|
||||||
<span :class="['task-status', `status-${task.status}`]">{{ statusText(task.status) }}</span>
|
<span :class="['task-status', `status-${task.status}`]">{{ statusText(task.status) }}</span>
|
||||||
<span v-if="task.status === 'failed' && task.error_category" class="error-cat-badge">
|
<span v-if="task.status === 'failed' && task.error_category" class="error-cat-badge">
|
||||||
{{ errorCategoryLabel(task.error_category) }}
|
{{ errorCategoryLabel(task.error_category) }}
|
||||||
@ -365,9 +365,9 @@ const errorCategoryLabel = (cat) => {
|
|||||||
.config-table th:nth-child(2) { width: 14%; }
|
.config-table th:nth-child(2) { width: 14%; }
|
||||||
.config-table th:nth-child(3) { width: 8%; }
|
.config-table th:nth-child(3) { width: 8%; }
|
||||||
.config-table th:nth-child(4) { width: 10%; }
|
.config-table th:nth-child(4) { width: 10%; }
|
||||||
.config-table th:nth-child(5) { width: 10%; }
|
.config-table th:nth-child(5) { width: 12%; }
|
||||||
.config-table th:nth-child(6) { width: 16%; }
|
.config-table th:nth-child(6) { width: 16%; }
|
||||||
.config-table th:nth-child(7) { width: 28%; }
|
.config-table th:nth-child(7) { width: 26%; }
|
||||||
.config-table tr:hover { background: #fafafa; }
|
.config-table tr:hover { background: #fafafa; }
|
||||||
|
|
||||||
.build-type-badge { padding: 2px 8px; border-radius: 4px; font-size: 12px; font-weight: 500; }
|
.build-type-badge { padding: 2px 8px; border-radius: 4px; font-size: 12px; font-weight: 500; }
|
||||||
@ -381,6 +381,8 @@ const errorCategoryLabel = (cat) => {
|
|||||||
.action-btn:hover { border-color: #1890ff; color: #1890ff; }
|
.action-btn:hover { border-color: #1890ff; color: #1890ff; }
|
||||||
|
|
||||||
.task-status { padding: 4px 12px; border-radius: 12px; font-size: 12px; font-weight: 500; }
|
.task-status { padding: 4px 12px; border-radius: 12px; font-size: 12px; font-weight: 500; }
|
||||||
|
.status-cell { white-space: normal !important; overflow: visible !important; text-overflow: clip !important; }
|
||||||
|
.status-cell .task-status, .status-cell .error-cat-badge { display: inline-block; margin-bottom: 4px; }
|
||||||
.status-pending { background: #f0f0f0; color: #666; }
|
.status-pending { background: #f0f0f0; color: #666; }
|
||||||
.status-running { background: #e6f7ff; color: #1890ff; }
|
.status-running { background: #e6f7ff; color: #1890ff; }
|
||||||
.status-completed { background: #f6ffed; color: #52c41a; }
|
.status-completed { background: #f6ffed; color: #52c41a; }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user