index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. <script setup>
  2. import {onMounted, reactive, ref} from 'vue'
  3. import {ElMessage, ElMessageBox} from 'element-plus'
  4. import {Building2, Calendar, Edit, Plus, Trash2} from 'lucide-vue-next'
  5. import request from "@/utils/request.js"
  6. // 响应式数据
  7. const developmentList = ref([])
  8. const loading = ref(false)
  9. const dialogVisible = ref(false)
  10. const editMode = ref(false)
  11. const currentItem = ref(null)
  12. // 表单数据
  13. const formData = reactive({
  14. year: '',
  15. processDescription: ''
  16. })
  17. // 分页数据
  18. const pagination = reactive({
  19. pageNum: 1,
  20. pageSize: 15, // 增加每页显示数量
  21. total: 0
  22. })
  23. // 获取列表数据
  24. const getList = async () => {
  25. loading.value = true
  26. try {
  27. const res = await request.get("/aboutDevelopmentHistory/findByPage", {
  28. params: {
  29. pageNum: pagination.pageNum,
  30. pageSize: pagination.pageSize
  31. }
  32. })
  33. if (res.code !== 200) {
  34. ElMessage.error(res.msg)
  35. return
  36. }
  37. developmentList.value = res.data.records
  38. pagination.total = res.data.total
  39. } catch (error) {
  40. ElMessage.error('获取数据失败')
  41. } finally {
  42. loading.value = false
  43. }
  44. }
  45. // 添加数据
  46. const add = async (data) => {
  47. const res = await request.post("/aboutDevelopmentHistory/save", {
  48. year: data.year,
  49. processDescription: data.processDescription
  50. })
  51. if (res.code !== 200) {
  52. ElMessage.error(res.msg)
  53. return false
  54. }
  55. ElMessage.success(res.msg)
  56. return true
  57. }
  58. // 更新数据
  59. const update = async (data) => {
  60. const res = await request.post("/aboutDevelopmentHistory/update", {
  61. id: currentItem.value.id,
  62. year: data.year,
  63. processDescription: data.processDescription
  64. })
  65. if (res.code !== 200) {
  66. ElMessage.error(res.msg)
  67. return false
  68. }
  69. ElMessage.success(res.msg)
  70. return true
  71. }
  72. //根据Id查询单个
  73. const getById = async (id) => {
  74. const res = await request.get("/aboutDevelopmentHistory/getById/"+ id)
  75. if (res.code !== 200) {
  76. ElMessage.error(res.msg)
  77. return
  78. }
  79. currentItem.value = res.data
  80. }
  81. // 删除数据
  82. const deleteBatch = async (ids) => {
  83. const res = await request.post("/aboutDevelopmentHistory/deleteBatch", ids)
  84. if (res.code !== 200) {
  85. ElMessage.error(res.msg)
  86. return false
  87. }
  88. ElMessage.success(res.msg)
  89. return true
  90. }
  91. // 打开添加对话框
  92. const openAddDialog = () => {
  93. editMode.value = false
  94. formData.year = ''
  95. formData.processDescription = ''
  96. dialogVisible.value = true
  97. }
  98. // 打开编辑对话框
  99. const openEditDialog = (item) => {
  100. editMode.value = true
  101. getById(item.id)
  102. formData.year = item.year
  103. formData.processDescription = item.processDescription
  104. dialogVisible.value = true
  105. }
  106. // 确认提交
  107. const handleSubmit = async () => {
  108. if (!formData.year || !formData.processDescription) {
  109. ElMessage.warning('请填写完整信息')
  110. return
  111. }
  112. const success = editMode.value
  113. ? await update(formData)
  114. : await add(formData)
  115. if (success) {
  116. dialogVisible.value = false
  117. getList()
  118. }
  119. }
  120. // 删除确认
  121. const handleDelete = async (item) => {
  122. try {
  123. await ElMessageBox.confirm('确定要删除这条发展历程吗?', '提示', {
  124. confirmButtonText: '确定',
  125. cancelButtonText: '取消',
  126. type: 'warning'
  127. })
  128. const success = await deleteBatch([item.id])
  129. if (success) {
  130. getList()
  131. }
  132. } catch {
  133. // 用户取消删除
  134. }
  135. }
  136. // 添加分页变化处理函数
  137. const handlePageChange = (page) => {
  138. pagination.pageNum = page
  139. getList()
  140. }
  141. const handleSizeChange = (size) => {
  142. pagination.pageSize = size
  143. pagination.pageNum = 1
  144. getList()
  145. }
  146. onMounted(() => {
  147. getList()
  148. })
  149. </script>
  150. <template>
  151. <div class="min-h-screen bg-gradient-to-br from-blue-50 via-indigo-50 to-purple-50 p-6">
  152. <!-- 页面头部 -->
  153. <div class="max-w-6xl mx-auto mb-8">
  154. <div class="text-center mb-8">
  155. <div class="inline-flex items-center justify-center w-16 h-16 bg-gradient-to-r from-blue-500 to-purple-600 rounded-full mb-4">
  156. <Building2 class="w-8 h-8 text-white" />
  157. </div>
  158. <h1 class="text-4xl font-bold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent mb-2">
  159. 公司发展历程
  160. </h1>
  161. <p class="text-gray-600 text-lg">见证我们的成长足迹,共创美好未来</p>
  162. </div>
  163. <!-- 添加按钮 -->
  164. <div class="flex justify-center mb-8">
  165. <button
  166. @click="openAddDialog"
  167. class="inline-flex items-center px-6 py-3 bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-full hover:from-blue-600 hover:to-purple-700 transform hover:scale-105 transition-all duration-200 shadow-lg hover:shadow-xl"
  168. >
  169. <Plus class="w-5 h-5 mr-2" />
  170. 添加发展历程
  171. </button>
  172. </div>
  173. </div>
  174. <!-- 时间线内容 -->
  175. <div class="max-w-7xl mx-auto">
  176. <!-- 加载状态 -->
  177. <div v-if="loading" class="flex justify-center py-12">
  178. <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500"></div>
  179. </div>
  180. <!-- 发展历程卡片网格布局 -->
  181. <div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 mb-8">
  182. <div
  183. v-for="(item, index) in developmentList"
  184. :key="item.id"
  185. class="group"
  186. >
  187. <div class="bg-white rounded-2xl shadow-lg hover:shadow-2xl transform hover:-translate-y-2 transition-all duration-300 overflow-hidden border border-gray-100 h-80 flex flex-col">
  188. <!-- 卡片头部 -->
  189. <div class="bg-gradient-to-r from-blue-500 to-purple-600 p-4 relative overflow-hidden flex-shrink-0">
  190. <div class="flex items-center justify-between relative z-10">
  191. <div class="flex items-center text-white">
  192. <Calendar class="w-5 h-5 mr-2" />
  193. <span class="text-2xl font-bold">{{ item.year }}</span>
  194. <span class="ml-2 text-blue-100">年</span>
  195. </div>
  196. <div class="flex space-x-2 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
  197. <button
  198. @click="openEditDialog(item)"
  199. class="p-2 bg-white/20 hover:bg-white/30 rounded-lg transition-colors duration-200"
  200. >
  201. <Edit class="w-4 h-4 text-white" />
  202. </button>
  203. <button
  204. @click="handleDelete(item)"
  205. class="p-2 bg-white/20 hover:bg-red-500/50 rounded-lg transition-colors duration-200"
  206. >
  207. <Trash2 class="w-4 h-4 text-white" />
  208. </button>
  209. </div>
  210. </div>
  211. <!-- 装饰性波浪 -->
  212. <div class="absolute -bottom-1 left-0 w-full h-4 bg-white rounded-t-full"></div>
  213. <!-- 装饰性圆圈 -->
  214. <div class="absolute -top-4 -right-4 w-16 h-16 bg-white/10 rounded-full"></div>
  215. <div class="absolute -top-2 -right-2 w-8 h-8 bg-white/20 rounded-full"></div>
  216. </div>
  217. <!-- 卡片内容 - 添加固定高度和文本截断 -->
  218. <div class="p-6 flex-1 flex flex-col min-h-0">
  219. <div class="flex-1 mb-4 overflow-hidden">
  220. <p class="text-gray-700 leading-relaxed text-base line-clamp-5">
  221. {{ item.processDescription }}
  222. </p>
  223. </div>
  224. <div class="text-xs text-gray-400 border-t pt-3 flex-shrink-0">
  225. 创建时间: {{ new Date(item.createTime).toLocaleDateString() }}
  226. </div>
  227. </div>
  228. <!-- 装饰性底部渐变 -->
  229. <div class="h-1 bg-gradient-to-r from-blue-400 to-purple-500 flex-shrink-0"></div>
  230. </div>
  231. </div>
  232. </div>
  233. <!-- 添加分页组件 -->
  234. <div v-if="!loading && developmentList.length > 0" class="flex justify-center">
  235. <el-pagination
  236. v-model:current-page="pagination.pageNum"
  237. v-model:page-size="pagination.pageSize"
  238. :page-sizes="[12, 15, 20, 30]"
  239. :total="pagination.total"
  240. layout="total, sizes, prev, pager, next, jumper"
  241. @size-change="handleSizeChange"
  242. @current-change="handlePageChange"
  243. class="bg-white rounded-lg shadow-md p-4"
  244. />
  245. </div>
  246. <!-- 空状态 -->
  247. <div v-if="!loading && developmentList.length === 0" class="text-center py-12">
  248. <div class="w-24 h-24 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-4">
  249. <Building2 class="w-12 h-12 text-gray-400" />
  250. </div>
  251. <p class="text-gray-500 text-lg">暂无发展历程数据</p>
  252. <p class="text-gray-400 text-sm mt-2">点击上方按钮添加第一条发展历程</p>
  253. </div>
  254. </div>
  255. <!-- 添加/编辑对话框 -->
  256. <el-dialog
  257. v-model="dialogVisible"
  258. :title="editMode ? '编辑发展历程' : '添加发展历程'"
  259. width="500px"
  260. :before-close="() => dialogVisible = false"
  261. >
  262. <div class="space-y-6">
  263. <div>
  264. <label class="block text-sm font-medium text-gray-700 mb-2">年份</label>
  265. <el-input
  266. v-model="formData.year"
  267. type="number"
  268. placeholder="请输入年份"
  269. class="w-full"
  270. />
  271. </div>
  272. <div>
  273. <label class="block text-sm font-medium text-gray-700 mb-2">历程描述</label>
  274. <el-input
  275. v-model="formData.processDescription"
  276. type="textarea"
  277. :rows="4"
  278. placeholder="请输入发展历程描述"
  279. class="w-full"
  280. />
  281. </div>
  282. </div>
  283. <template #footer>
  284. <div class="flex justify-end space-x-3">
  285. <el-button @click="dialogVisible = false">取消</el-button>
  286. <el-button type="primary" @click="handleSubmit">
  287. {{ editMode ? '更新' : '添加' }}
  288. </el-button>
  289. </div>
  290. </template>
  291. </el-dialog>
  292. </div>
  293. </template>
  294. <style scoped>
  295. /* 自定义滚动条 */
  296. ::-webkit-scrollbar {
  297. width: 6px;
  298. }
  299. ::-webkit-scrollbar-track {
  300. background: #f1f1f1;
  301. border-radius: 3px;
  302. }
  303. ::-webkit-scrollbar-thumb {
  304. background: linear-gradient(to bottom, #3b82f6, #8b5cf6);
  305. border-radius: 3px;
  306. }
  307. ::-webkit-scrollbar-thumb:hover {
  308. background: linear-gradient(to bottom, #2563eb, #7c3aed);
  309. }
  310. /* 卡片动画 */
  311. @keyframes slideInLeft {
  312. from {
  313. opacity: 0;
  314. transform: translateX(-50px);
  315. }
  316. to {
  317. opacity: 1;
  318. transform: translateX(0);
  319. }
  320. }
  321. @keyframes slideInRight {
  322. from {
  323. opacity: 0;
  324. transform: translateX(50px);
  325. }
  326. to {
  327. opacity: 1;
  328. transform: translateX(0);
  329. }
  330. }
  331. @keyframes fadeInUp {
  332. from {
  333. opacity: 0;
  334. transform: translateY(30px);
  335. }
  336. to {
  337. opacity: 1;
  338. transform: translateY(0);
  339. }
  340. }
  341. .group {
  342. animation: fadeInUp 0.6s ease-out;
  343. animation-fill-mode: both;
  344. }
  345. .group:nth-child(1) { animation-delay: 0.1s; }
  346. .group:nth-child(2) { animation-delay: 0.2s; }
  347. .group:nth-child(3) { animation-delay: 0.3s; }
  348. .group:nth-child(4) { animation-delay: 0.4s; }
  349. .group:nth-child(5) { animation-delay: 0.5s; }
  350. .group:nth-child(6) { animation-delay: 0.6s; }
  351. /* 分页组件样式优化 */
  352. :deep(.el-pagination) {
  353. --el-pagination-button-color: #6366f1;
  354. --el-pagination-hover-color: #4f46e5;
  355. }
  356. /* 添加文本截断样式 */
  357. .line-clamp-5 {
  358. display: -webkit-box;
  359. -webkit-line-clamp: 5;
  360. -webkit-box-orient: vertical;
  361. overflow: hidden;
  362. text-overflow: ellipsis;
  363. }
  364. </style>