mirror of
https://github.com/ccmjga/zhilu-admin
synced 2026-03-24 11:53:41 +08:00
mobile version 2.0
This commit is contained in:
@@ -1,28 +1,24 @@
|
||||
<template>
|
||||
<nav class="flex mb-3 sm:mb-4 md:mb-5" aria-label="Breadcrumb">
|
||||
<ol class="inline-flex items-center space-x-1 text-xs sm:text-sm font-medium md:space-x-2">
|
||||
<nav class="flex mb-4" aria-label="Breadcrumb">
|
||||
<ol class="inline-flex items-center space-x-1 sm:space-x-2 text-sm">
|
||||
<li class="inline-flex items-center">
|
||||
<RouterLink :to="{name: RouteName.USERVIEW}"
|
||||
class="inline-flex items-center text-gray-700 hover:text-primary-600">
|
||||
<svg class="w-4 h-4 sm:w-5 sm:h-5 me-1.5 sm:me-2 md:me-2.5" fill="currentColor" viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<RouterLink to="/" class="inline-flex items-center font-medium text-gray-500 hover:text-blue-600">
|
||||
<svg class="w-3.5 h-3.5 mr-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor"
|
||||
viewBox="0 0 20 20">
|
||||
<path
|
||||
d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z">
|
||||
</path>
|
||||
d="m19.707 9.293-2-2-7-7a1 1 0 0 0-1.414 0l-7 7-2 2a1 1 0 0 0 1.414 1.414L2 10.414V18a2 2 0 0 0 2 2h3a1 1 0 0 0 1-1v-4a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v4a1 1 0 0 0 1 1h3a2 2 0 0 0 2-2v-7.586l.293.293a1 1 0 0 0 1.414-1.414Z" />
|
||||
</svg>
|
||||
首页
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li v-for="name in names" :key="name">
|
||||
<li v-for="(name, index) in names" :key="index">
|
||||
<div class="flex items-center">
|
||||
<svg class="w-3 h-3 sm:w-4 sm:h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
|
||||
clip-rule="evenodd"></path>
|
||||
<svg class="w-3 h-3 text-gray-400 mx-1.5 sm:mx-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none" viewBox="0 0 6 10">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="m1 9 4-4-4-4" />
|
||||
</svg>
|
||||
<span class="ms-1 text-gray-400 hover:text-primary-600 md:ms-2">{{
|
||||
name }}</span>
|
||||
<span class="font-medium text-gray-500 truncate">{{ name }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
@@ -59,9 +59,9 @@ const sizeClasses = computed(() => {
|
||||
}
|
||||
switch (props.size) {
|
||||
case "xs":
|
||||
return "text-xs px-2.5 py-1.5";
|
||||
return "text-xs px-3 py-1.5";
|
||||
case "sm":
|
||||
return "text-xs px-3 py-2";
|
||||
return "text-sm px-3.5 py-2";
|
||||
case "lg":
|
||||
return "text-base px-5 py-3";
|
||||
case "xl":
|
||||
@@ -74,7 +74,7 @@ const sizeClasses = computed(() => {
|
||||
const iconSizeClasses = computed(() => {
|
||||
switch (props.size) {
|
||||
case "xs":
|
||||
return "w-3 h-3";
|
||||
return "w-3.5 h-3.5";
|
||||
case "sm":
|
||||
return "w-4 h-4";
|
||||
case "lg":
|
||||
@@ -82,7 +82,7 @@ const iconSizeClasses = computed(() => {
|
||||
case "xl":
|
||||
return "w-6 h-6";
|
||||
default:
|
||||
return "w-5 h-5";
|
||||
return "w-4.5 h-4.5";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
43
frontend/src/components/MobileCardList.vue
Normal file
43
frontend/src/components/MobileCardList.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<slot name="empty" v-if="items.length === 0"></slot>
|
||||
<div v-else v-for="(item, index) in items" :key="index"
|
||||
class="p-4 bg-white rounded-lg shadow relative border border-gray-100">
|
||||
<div class="flex justify-between items-start mb-3">
|
||||
<!-- 标题区域 -->
|
||||
<div class="flex items-center">
|
||||
<slot name="checkbox" :item="item" v-if="hasCheckbox"></slot>
|
||||
<div class="font-medium text-gray-900">
|
||||
<slot name="title" :item="item"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 状态区域 -->
|
||||
<div>
|
||||
<slot name="status" :item="item"></slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div class="text-sm text-gray-600 mb-3 space-y-2">
|
||||
<slot name="content" :item="item"></slot>
|
||||
</div>
|
||||
|
||||
<!-- 标签/分类区域 -->
|
||||
<div v-if="$slots.tags" class="flex flex-wrap gap-2 mb-3">
|
||||
<slot name="tags" :item="item"></slot>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮区域 -->
|
||||
<div class="flex justify-between items-center mt-4">
|
||||
<slot name="actions" :item="item"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup generic="T" lang="ts">
|
||||
defineProps<{
|
||||
items: T[];
|
||||
hasCheckbox?: boolean;
|
||||
}>();
|
||||
</script>
|
||||
@@ -2,7 +2,7 @@
|
||||
<div :id tabindex="-1"
|
||||
class="bg-gray-900/50 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full h-[calc(100%-1rem)] max-h-full">
|
||||
<div class="relative p-4 w-full max-w-xs sm:max-w-sm md:max-w-md max-h-full">
|
||||
<div class="relative bg-white rounded-lg shadow-sm">
|
||||
<div class="relative bg-white rounded-lg shadow">
|
||||
<button type="button" @click="closeModal"
|
||||
class="absolute top-3 end-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center">
|
||||
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
||||
@@ -11,22 +11,22 @@
|
||||
</svg>
|
||||
<span class="sr-only">Close modal</span>
|
||||
</button>
|
||||
<div class="p-4 md:p-5 text-center flex flex-col items-center gap-y-3 sm:gap-y-4">
|
||||
<svg class="w-12 h-12 sm:w-16 sm:h-16 mx-auto text-red-600 mt-4 sm:mt-5" fill="none" stroke="currentColor"
|
||||
<div class="p-5 md:p-6 text-center">
|
||||
<svg class="w-14 h-14 sm:w-16 sm:h-16 mx-auto text-red-600 mb-4" fill="none" stroke="currentColor"
|
||||
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<h3 class="mb-2 sm:mb-3 text-base sm:text-lg font-normal text-gray-500">
|
||||
<h3 class="mb-4 text-base sm:text-lg font-medium text-gray-800">
|
||||
{{ title }}
|
||||
</h3>
|
||||
<div class="flex flex-col sm:flex-row sm:justify-center gap-2 w-full sm:w-auto">
|
||||
<div class="flex justify-center items-center space-x-3 sm:space-x-4">
|
||||
<button type="button" @click="onSubmit"
|
||||
class="w-full sm:w-auto text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-xs sm:text-sm px-4 py-2 sm:px-5 sm:py-2.5 text-center">
|
||||
class="text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center min-w-[80px]">
|
||||
是
|
||||
</button>
|
||||
<button type="button" @click="closeModal"
|
||||
class="w-full sm:w-auto py-2 sm:py-2.5 px-4 sm:px-5 text-xs sm:text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100">否</button>
|
||||
class="py-2.5 px-5 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 min-w-[80px]">否</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<nav class="flex items-center flex-col md:flex-row flex-wrap justify-between py-3 sm:py-4 px-3 sm:px-5"
|
||||
<nav class="flex items-center flex-col md:flex-row flex-wrap justify-between py-4 px-3 sm:px-5"
|
||||
aria-label="Table navigation">
|
||||
<span class="text-xs sm:text-sm font-normal text-gray-500 mb-3 md:mb-0 block w-full md:inline md:w-auto">
|
||||
<span class="text-xs sm:text-sm font-normal text-gray-500 mb-4 md:mb-0 block w-full md:inline md:w-auto">
|
||||
显示
|
||||
<span class="font-semibold text-gray-900">
|
||||
{{ displayRange.start }}-{{ displayRange.end }}
|
||||
@@ -9,25 +9,25 @@
|
||||
共
|
||||
<span class="font-semibold text-gray-900">{{ total }}</span> 条
|
||||
</span>
|
||||
<ul class="inline-flex -space-x-px rtl:space-x-reverse text-xs sm:text-sm">
|
||||
<ul class="inline-flex -space-x-px rtl:space-x-reverse text-sm h-8">
|
||||
<li>
|
||||
<a href="#" @click.prevent="handlePageChangeClick(currentPage - 1)" :class="[
|
||||
'flex items-center justify-center px-2.5 h-7 sm:px-3 sm:h-8 ms-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-s-lg hover:bg-gray-100 hover:text-gray-700',
|
||||
'flex items-center justify-center px-3 h-8 ms-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-s-lg hover:bg-gray-100 hover:text-gray-700',
|
||||
{ 'opacity-50 cursor-not-allowed': isFirstPage }
|
||||
]">上一页</a>
|
||||
</li>
|
||||
<li v-for="page in pageNumbers" :key="page">
|
||||
<button @click.prevent="handlePageChangeClick(page)" :class="[
|
||||
'flex items-center justify-center px-2.5 h-7 sm:px-3 sm:h-8 leading-tight border border-gray-300 hover:bg-gray-100 hover:text-gray-700',
|
||||
'flex items-center justify-center px-3 h-8 leading-tight border border-gray-300 hover:bg-gray-100 hover:text-gray-700',
|
||||
currentPage === page
|
||||
? 'text-blue-600 bg-blue-50 hover:bg-blue-100 hover:text-blue-700'
|
||||
? 'text-blue-600 bg-blue-50 hover:bg-blue-100 hover:text-blue-700 font-medium'
|
||||
: 'text-gray-500 bg-white'
|
||||
]">{{ page }}</button>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<button @click.prevent="handlePageChangeClick(currentPage + 1)" :class="[
|
||||
'flex items-center justify-center px-2.5 h-7 sm:px-3 sm:h-8 leading-tight text-gray-500 bg-white border border-gray-300 rounded-e-lg hover:bg-gray-100 hover:text-gray-700',
|
||||
'flex items-center justify-center px-3 h-8 leading-tight text-gray-500 bg-white border border-gray-300 rounded-e-lg hover:bg-gray-100 hover:text-gray-700',
|
||||
{ 'opacity-50 cursor-not-allowed': isLastPage }
|
||||
]">下一页</button>
|
||||
</li>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class="bg-gray-900/50 hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
|
||||
<div class="relative p-4 w-full max-w-xs sm:max-w-sm md:max-w-md max-h-full">
|
||||
<!-- Modal content -->
|
||||
<div class="relative bg-white rounded-lg shadow-sm">
|
||||
<div class="relative bg-white rounded-lg shadow">
|
||||
<!-- Modal header -->
|
||||
<div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200">
|
||||
<h3 class="text-base sm:text-lg font-semibold text-gray-900">
|
||||
@@ -21,27 +21,27 @@
|
||||
</div>
|
||||
<!-- Modal body -->
|
||||
<form class="p-4 md:p-5">
|
||||
<div class="grid gap-4 mb-4 grid-cols-1 sm:grid-cols-2">
|
||||
<div class="col-span-full sm:col-span-2">
|
||||
<div class="space-y-4">
|
||||
<div class="w-full">
|
||||
<label for="name" class="block mb-2 text-sm font-medium text-gray-900">用户名</label>
|
||||
<input type="text" name="用户名" id="name" v-model="formData.username"
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5"
|
||||
required="true">
|
||||
</div>
|
||||
<div class="col-span-full sm:col-span-2">
|
||||
<label for="password" class="block mb-2 text-sm font-medium autocompletetext-gray-900">密码</label>
|
||||
<div class="w-full">
|
||||
<label for="password" class="block mb-2 text-sm font-medium text-gray-900">密码</label>
|
||||
<input type="password" id="password" autocomplete="new-password" v-model="formData.password"
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
|
||||
placeholder="编辑时非必填" required />
|
||||
</div>
|
||||
<div class="col-span-full sm:col-span-2">
|
||||
<div class="w-full">
|
||||
<label for="confirm_password" class="block mb-2 text-sm font-medium text-gray-900">确认密码</label>
|
||||
<input type="password" id="confirm_password" autocomplete="new-password"
|
||||
v-model="formData.confirmPassword"
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
|
||||
required placeholder="编辑时非必填" />
|
||||
</div>
|
||||
<div class="col-span-full sm:col-span-1">
|
||||
<div class="w-full">
|
||||
<label for="status" class="block mb-2 text-sm font-medium text-gray-900">状态</label>
|
||||
<select id="status" v-model="formData.enable"
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5">
|
||||
@@ -51,7 +51,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" @click.prevent="handleSubmit"
|
||||
class="w-auto text-sm px-4 py-2 text-white flex items-center bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-center self-start mt-5">
|
||||
class="mt-5 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center">
|
||||
保存
|
||||
</button>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user