基于vuestic-ui实战教程 - 页面篇

1. 简介

前面介绍了基本的内容比如如何获取动态数据,下面就到登录进来后的页面实现了,相信各位读者或多或少都有 element-ui+js 的实战经历,那么 vuestic-ui+ts 实现的页面又该如何写呢?带着疑问开启今天的学习(声明由于作者本人也不是搞前端的,所以不一定了解所有知识,这里只教大家如何快速上手以及自身遇到的问题)

2. 页面嵌入实现

在做的项目需要嵌入一个第三方页面,最常见的方法就是使用iframe(当然还有其他的实现,感兴趣的读者可以自行研究)我就以nacos的监控页面为例子,定义如下的 index.vue 页面

<template><iframeid="page"src="http://localhost:8848/nacos" style="width: 100%; height:100%"></iframe>
</template>

然后成功运行到网页端测试,发现页面并不能正常显示,console中报错信息如下,hash出问题又是跨域出问题,一开始就给我搞蒙了查了各种资料都不嫩解决问题,而且在浏览器中输入网址又显示正常

在这里插入图片描述
细看网址发现当输入前缀后会自动跳转,而iframe中引用的src无法发起跨域请求,自然就会报错。

输入 http://localhost:8848/nacos/ 会自动跳转到如下链接(注意#
http://localhost:8848/nacos/#/configurationManagement?dataId=&group=&appName=&namespace=&pageSize=&pageNo=

在网址中,井号(#)后面的部分被称为URL的片段标识符(fragment identifier),常用于指定网页中的某个特定的位置或者元素。

当访问一个带有"#"后面内容的网站时,浏览器会自动滚动到与该标识符相对应的页面区域。例如,在单页应用(SPA)中,不同的页面内容往往对应不同的标识符,用户通过改变URL中的哈希值可以无需重新加载页面而直接导航至相应的内容区域。

所以做出如下改进,此时页面已经能正常显示出来了,但是显示的大小不对,如下图所示,这么大的版面只给我显示这一点,明明设置的style高宽都是100%啊

<template><iframeid="child"src="http://localhost:8848/nacos/#/configurationManagement?dataId=&group=&appName=&namespace=&pageSize=&pageNo="style="width: 100%; height:100%"></iframe>
</template>

在这里插入图片描述

经过查阅资料发现设置是有讲究的,常见的两种区别如下

  • 100vh : vh是一个相对单位,表示视口高度的1%。因此,height: 100vh意味着元素的高设置为视口高度的100%,即元素将占据整个视口的高度。无论该元素的父级元素有多大,或者该元素是否包含内容,使用height: 100vh都会使元素高度与视口高度一致,即使没有内容时也会撑开至屏幕高度。
  • 100%:百分比值%是相对于父元素的尺寸来计算的。当使用height: 100%时,元素的高将设置为直接父元素高度的100%,这意味着元素将尽可能地占据父元素的高度。如果父元素的大小没有明确定义或者小于视口大小,那么该元素的实际高度可能会小于视口高度。

在我们这个例子中因为不能确定父级元素的大小,所以推荐使用vh而不是% 为度量单位,修改过后就能正常大小显示啦

3. 页面编写展示动态数据

直接仿照他给好的页面users实例,我们可以自己实现一个类似的页面来动态获取数据,整体代码架构如下图(UserAvatar未作大修改),可以看到其实是跟给定案例的架构差不多的,右边的是之前讲到过的动态与后端交互的一些api方法

在这里插入图片描述

3.1 index页面

首先通过useUsers方法(3.2)定义好的获取UsersTable渲染所需要的一些数据,比如原始数据users,做分页的pagination , 可供模糊查询的filters , 还有每列上排序的组件sorting ,以及对数据增删改的api(这里api的命名自定义,在当前页面中唯一使用),具体的定义意义可以看代码中的注释,基本上都有提及,下面就重点讲讲自定义组件的实现

对于代码const userToEdit = ref<UserData | null>(null) 在 TypeScript 中十分常见,ref 是一个用于创建响应式引用的函数

ref函数的主要应用场景是在需要对简单类型值进行响应式处理时。例如,当你有一个基本类型的变量(如数字、字符串等),并希望它的改变能够触发视图或其他部分的自动更新时,你可以使用ref。这是因为Proxy对象只能拦截对象属性的访问,而不是直接对一个变量的改变进行拦截。通过ref,你可以将简单类型的值包装在一个形式为{ value: T }的对象中,这样在修改值时就可以通过.value属性来触发响应式更新。

在这个例子中,userToEdit 是一个响应式引用,它的类型是 UserData | null。这意味着 userToEdit 可以存储一个 UserData 类型的对象或者 null。

<script setup lang="ts">
import { ref } from 'vue'
import UsersTable from './widgets/UsersTable.vue'
import EditUserForm from './widgets/EditUserForm.vue'
import { UserData } from '@/api/system/sysUser/types'
import { useUsers } from '../sysUser/composables/useUsers'
import { useModal, useToast } from 'vuestic-ui'
import { onPageRender } from '@/utils/tokenMonitor'const doShowEditUserModal = ref(false) let { users, isLoading , filters, sorting, pagination , ...api } = useUsers()
// 当前需要修改的数据,edit就是当前行,而add是null,如下两个function
const userToEdit = ref<UserData | null>(null)
// 动态刷新token
window.addEventListener('load', () => {onPageRender();
});
// 展示的是edit
const showEditUserModal = (user: UserData) => {userToEdit.value = userdoShowEditUserModal.value = true
}
// 展示的是add
const showAddUserModal = () => {userToEdit.value = nulldoShowEditUserModal.value = true
}const { init: notify } = useToast()
// 添加/修改方法
const onUserSaved = async (user: UserData) => {console.log(userToEdit.value)if (userToEdit.value) {console.log("edit")api.update(user).then(data => notify({message: `${user.name} has been update`,color: 'success',})).catch(() => notify({message: `${user.name} updated fail`,color: 'dangerous',})
)} else {api.add(user).then(data => notify({message: `${user.name} has been add`,color: 'success',})).catch(() => notify({message: `${user.name} add fail`,color: 'dangerous',})
)}
}
// 删除方法
const onUserDelete = async (user: UserData) => {api.remove(user.id).then(data => notify({message: `${user.name} has been delete`,color: 'success',})).catch(() => notify({message: `${user.name} deleted fail`,color: 'dangerous',})
)}
// 点击cancel按钮后弹出的友好提示
const editFormRef = ref()
const { confirm } = useModal()const beforeEditFormModalClose = async (hide: () => unknown) => {if (editFormRef.value.isFormHasUnsavedChanges) {const agreed = await confirm({maxWidth: '380px',message: 'Form has unsaved changes. Are you sure you want to close it?',size: 'small',})if (agreed) {hide()}} else {hide()}
}
</script><template><h1 class="page-title">Users</h1><VaCard><VaCardContent><div class="flex flex-col md:flex-row gap-2 mb-2 justify-between"><div class="flex flex-col md:flex-row gap-2 justify-start"><VaButtonTogglev-model="filters.isActive "color="background-element"border-color="background-element":options="[{ label: 'Active', value: 1 },{ label: 'Inactive', value: 0 },]"/><VaInput v-model="filters.search" placeholder="Search"><template #prependInner><VaIcon name="search" color="secondary" size="small" /></template></VaInput></div><VaButton @click="showAddUserModal">Add User</VaButton></div><UsersTablev-model:sorting-order="sorting.sortingOrder"v-model:sort-by="sorting.sortBy":users="users":loading="isLoading":pagination="pagination"@editUser="showEditUserModal"@deleteUser="onUserDelete"/></VaCardContent></VaCard><VaModalv-slot="{ cancel, ok }"v-model="doShowEditUserModal"size="small"mobile-fullscreenclose-buttonhide-default-actions:before-cancel="beforeEditFormModalClose"><h1 class="va-h5">{{ userToEdit ? 'Edit user' : 'Add user' }}</h1><EditUserFormref="editFormRef":user="userToEdit":save-button-label="userToEdit ? 'Save' : 'Add'"@close="cancel"@save="(user) => {onUserSaved(user)ok()}"/></VaModal>
</template>

自定义的组件在当前的vue页面中体现在 <EditUserForm> <UsersTable>也就是前面代码架构时提到的一些组件(对于自定义组件的实现需要跳转到定义出看更容易理解) 而在下图的实例中最上面的三个红色框(UsersTable之上的)定义在VaCardContent的第2个div中实现,具体需要注意的就是VaButtonToggle绑定的option value值应该是number类型(为了与数据库中定义的类型对应,当然读者想换成boolean也可以的,只需要全局上下文保持一致就好)

3.2 UsersTable组件定义

在这里插入图片描述

原有的table组件不够美观,想要自己定义的时候就可以用该模板,对于模板的实例如上图我用红色框框框出来的就是几个加入的组件,下面就分别在代码中实现

3.3 defineVaDataTableColumns 、defineProps 、 defineEmits

  • 第一个columns常量,它使用defineVaDataTableColumns函数来创建一个数据表格的列配置。这个函数接收一个包含多个对象的数组,每个对象代表一个列的配置信息。注意key要与后端封装的实体类命名保持一致(sortable 表示该列是否选择排序)

  • 第二个props常量,它使用defineProps函数来定义组件的属性。这个函数接收一个对象,对象中的每个键值对表示一个属性的定义。(在应用的时候使用 :key="value" 的格式实现,这里的value为引用对象),这里截了一张图供读者对应参考实现放在后面讲在这里插入图片描述

  • 第三个emit常量,它使用defineEmits函数来定义组件可以触发的事件。这个函数接收一个对象,对象中的每个键值对表示一个事件的定义。在这个例子中,定义了4个事件,分别是edit-user、delete-user、update:sortBy和update:sortingOrder。

3.4 VaPagination 做分页

根据其提供好的组件来实现分页功能,双向绑定的值是我们在props定义的一些pagination

<script setup lang="ts">
import { defineVaDataTableColumns, useModal } from 'vuestic-ui'
import { UserData } from '@/api/system/sysUser/types'
import UserAvatar from './UserAvatar.vue'
import { PropType, computed, toRef } from 'vue'
import { Pagination, Sorting } from '@/api/system/sysUser/types'
import { useVModel } from '@vueuse/core'const columns = defineVaDataTableColumns([{ label: 'Full Name', key: 'name', sortable: true },{ label: 'Username', key: 'username', sortable: true },{ label: 'Email', key: 'email', sortable: true },{ label: 'Phone', key: 'phone', sortable: true },{ label: 'Role', key: 'roleList', sortable: true },{ label: ' ', key: 'actions', align: 'right' },
])const props = defineProps({users: {type: Array as PropType<UserData[]>,required: true,},loading: { type: Boolean, default: false },pagination: { type: Object as PropType<Pagination>, required: true },sortBy: { type: String as PropType<Sorting['sortBy']>, required: true },sortingOrder: { type: String as PropType<Sorting['sortingOrder']>, required: true },
})const emit = defineEmits<{(event: 'edit-user', user: UserData): void(event: 'delete-user', user: UserData): void(event: 'update:sortBy', sortBy: Sorting['sortBy']): void(event: 'update:sortingOrder', sortingOrder: Sorting['sortingOrder']): void
}>()
// 使用pros传进来的对象来渲染页面
const users = toRef(props, 'users')
const sortByVModel = useVModel(props, 'sortBy', emit)
const sortingOrderVModel = useVModel(props, 'sortingOrder', emit)
//每次引用时候使用compute计算当前的页数
const totalPages = computed(() => Math.ceil(props.pagination.total / props.pagination.perPage))const { confirm } = useModal()
// 点击cancel取消的友好提示
const onUserDelete = async (user: UserData) => {const agreed = await confirm({title: 'Delete user',message: `Are you sure you want to delete ${user.username}?`,okText: 'Delete',cancelText: 'Cancel',size: 'small',maxWidth: '380px',})if (agreed) {emit('delete-user', user)}
}</script><template><VaDataTablev-model:sort-by="sortByVModel"v-model:sorting-order="sortingOrderVModel":columns="columns":items="users":loading="$props.loading"><template #cell(name)="{ rowData }"><div class="flex items-center gap-2 max-w-[230px] ellipsis"><UserAvatar :user="rowData as UserData" size="small" />{{ rowData.name }}</div></template><template #cell(username)="{ rowData }"><div class="max-w-[120px] ellipsis">{{ rowData.username }}</div></template><template #cell(email)="{ rowData }"><div class="ellipsis max-w-[230px]">{{ rowData.email }}</div></template><template #cell(roleList)="{ rowData }"><div class="ellipsis max-w-[230px]"><template v-for="roleItem in rowData.roleList" :key="roleItem.id"><div><VaBadge :text="roleItem.roleName"></VaBadge></div></template></div></template><template #cell(phone)="{ rowData }"><div class="ellipsis max-w-[230px]">{{ rowData.phone }}</div></template><template #cell(actions)="{ rowData }"><div class="flex gap-2 justify-end"><VaButtonpreset="primary"size="small"icon="mso-edit"aria-label="Edit user"@click="$emit('edit-user', rowData as UserData)"/><VaButtonpreset="primary"size="small"icon="mso-delete"color="danger"aria-label="Delete user"@click="onUserDelete(rowData as UserData)"/></div></template></VaDataTable><div class="flex flex-col-reverse md:flex-row gap-2 justify-between items-center py-2"><div><b>{{ $props.pagination.total }} results.</b>Results per page<VaSelect v-model="$props.pagination.perPage" class="!w-20" :options="[10, 50, 100]" /></div><div v-if="totalPages > 1" class="flex"><VaButtonpreset="secondary"icon="va-arrow-left"aria-label="Previous page":disabled="$props.pagination.page === 1"@click="$props.pagination.page--"/><VaButtonclass="mr-2"preset="secondary"icon="va-arrow-right"aria-label="Next page":disabled="$props.pagination.page === totalPages"@click="$props.pagination.page++"/><VaPaginationv-model="$props.pagination.page"buttons-preset="secondary":pages="totalPages":visible-pages="5":boundary-links="false":direction-links="false"/></div></div>
</template><style lang="scss" scoped>
.va-data-table {::v-deep(.va-data-table__table-tr) {border-bottom: 1px solid var(--va-background-border);}
}
</style>

3.3 types定义

上面的代码中提到了特别多的类型比如UserData 、Pagination 、Sorting 等等,下面就给出这些类型的定义(如下代码定义在api/system/sysUser/types.ts 中)前面两个完全根据后端的实体类对应,而下面三个就是渲染所需要用到的一些类型定义

import { RoleData } from "../sysRole/types"/* sysUser参数类型 */
export interface UserData {id: number,username: string,email: string,password: string,phone: string,headUrl: string,name: string,status: number,roleList: RoleData[]}/* sysUser参数类型 export interface RoleData {id: number,roleName: string,roleCode: string,description: string}
*/// Simulate API callsexport type Pagination = {page: numberperPage: numbertotal: number
}export type Sorting = {sortBy: keyof UserData | undefinedsortingOrder: 'asc' | 'desc' | null
}export type Filters = {isActive: number //与数据库status类型保持一致search: string
}

3.4 EditUserForm 实现

下面就来到实现点击add 或者 edit按钮弹窗组件实现了,实现与UserTable其实差不多

注意在默认用户defaultNewUser中定义的参数与后端一一对应,如果不想定义那么多参数可以使用一个UserVo实体类,前端封装自己想要的UserVo实体(比如我就想要name和email)后端接收到该数据再new User对其进行封装,没有传递的参数就是null, 这样就解决了ts中报错类型参数不一致问题

<script setup lang="ts">
import { PropType, computed, ref, watch } from 'vue'
import { useForm } from 'vuestic-ui'
import { UserData } from '@/api/system/sysUser/types'
import RoleApi from '@/api/system/sysRole'
import { useToast } from 'vuestic-ui'
import UserAvatar from './UserAvatar.vue'
import { validators } from '@/services/utils'// 定义传递的对象 user即是用户数据,saveButtonLabel即是判断当前的操作类型
const props = defineProps({user: {type: Object as PropType<UserData | null>,default: null,},saveButtonLabel: {type: String,default: 'Save',},
})const { init: notify } = useToast()
// 默认用户 
const defaultNewUser: UserData = {id: -1,username: '',name: '',password: '123456',phone: '',headUrl: '',email: '',status: 1,roleList: [],
}const newUser = ref<UserData>({ ...defaultNewUser })
// 是否有修改过表单
const isFormHasUnsavedChanges = computed(() => {return Object.keys(newUser.value).some((key) => {if (key === 'avatar' ) {return false}return newUser.value[key as keyof UserData] !== (props.user ?? defaultNewUser)?.[key as keyof UserData]})
})defineExpose({isFormHasUnsavedChanges,
})
// 监控修改当前用户的头像
watch(() => props.user,() => {if (!props.user) {return}newUser.value = {...props.user,headUrl: props.user.headUrl || '',}},{ immediate: true },
)const avatar = ref<File>()const makeAvatarBlobUrl = (avatar: File) => {return URL.createObjectURL(avatar)
}watch(avatar, (newAvatar) => {newUser.value.headUrl = newAvatar ? makeAvatarBlobUrl(newAvatar) : ''
})const form = useForm('add-user-form')const emit = defineEmits(['close', 'save'])const onSave = () => {if (form.validate()) {emit('save', newUser.value)}
}</script><template><VaForm v-slot="{ isValid }" ref="add-user-form" class="flex-col justify-start items-start gap-4 inline-flex w-full"><VaFileUploadv-model="avatar"type="single"hide-file-listclass="self-stretch justify-start items-center gap-4 inline-flex"><UserAvatar :user="newUser" size="large" /><VaButton preset="primary" size="small">Add image</VaButton><VaButtonv-if="avatar"preset="primary"color="danger"size="small"icon="delete"class="z-10"@click.stop="avatar = undefined"/></VaFileUpload><div class="self-stretch flex-col justify-start items-start gap-4 flex"><div class="flex gap-4 flex-col sm:flex-row w-full"><VaInputv-model="newUser.name"label="Name"class="w-full sm:w-1/2":rules="[validators.required]"name="name"/><VaInputv-model="newUser.username"label="Username"class="w-full sm:w-1/2":rules="[validators.required]"name="username"/></div><div class="flex gap-4 flex-col sm:flex-row w-full"><VaInputv-model="newUser.email"label="Email"class="w-full sm:w-1/2":rules="[validators.required, validators.email]"name="email"/><VaInputv-model="newUser.phone"label="Phone"class="w-full sm:w-1/2":rules="[validators.required]"name="phone"/></div><div class="flex items-center w-1/2 mt-4"><VaCheckbox v-model.number="newUser.status" label="Active" class="w-full" name="status" /></div></div><div class="flex gap-2 flex-col-reverse items-stretch justify-end w-full sm:flex-row sm:items-center"><VaButton preset="secondary" color="secondary" @click="$emit('close')">Cancel</VaButton><VaButton :disabled="!isValid" @click="onSave">{{ saveButtonLabel }}</VaButton></div></div></VaForm>
</template>

3.5 useUser api编写

主要实现的就是useUser这个方法,方法中又调用了getUsers 来动态获取数据库数据await UserApi.listAll(),并根据index中传回来的props属性生成当前的Pagination Filters Sorting三个参数(每一次改变都会重新生成)

import { Ref, ref, unref, watch } from 'vue'
import { UserData , type Filters, Pagination, Sorting } from '@/api/system/sysUser/types'
import UserApi from '@/api/system/sysUser'
import { watchIgnorable } from '@vueuse/core'const makePaginationRef = () => ref<Pagination>({ page: 1, perPage: 10, total: 0 })
const makeSortingRef = () => ref<Sorting>({ sortBy: 'name', sortingOrder: null })
const makeFiltersRef = () => ref<Partial<Filters>>({ isActive: 1, search: '' })const getSortItem = (obj: any, sortBy: string) => {return obj[sortBy]
}export const getUsers =  async (filters: Partial<Filters & Pagination & Sorting>) => {try {let users: UserData[] = []// Fetch the user data using UserApi.listAll()const data = await UserApi.listAll()console.log("-1>>>>",data)users = datalet filteredUsers = usersconsole.log("0>>>>",filteredUsers)const { isActive, search, sortBy, sortingOrder } = filters// Apply filter based on isActivefilteredUsers = filteredUsers.filter((user) => user.status === isActive)console.log("1>>>>",filteredUsers)// Apply filter based on searchif (search) {filteredUsers = filteredUsers.filter((user) => user.name.toLowerCase().includes(search.toLowerCase()))}console.log("2>>>>",filteredUsers)// Apply sortingif (sortBy && sortingOrder) {filteredUsers = filteredUsers.sort((a, b) => {const first = getSortItem(a, sortBy)const second = getSortItem(b, sortBy)if (first > second) {return sortingOrder === 'asc' ? 1 : -1}if (first < second) {return sortingOrder === 'asc' ? -1 : 1}return 0})}console.log("3>>>>",filteredUsers)const { page = 1, perPage = 10 } = filters || {}// Return the filtered and paginated datareturn {data: filteredUsers.slice((page - 1) * perPage, page * perPage),pagination: {page,perPage,total: filteredUsers.length,},}} catch (error) {// Handle error here}
}export const useUsers = (options?: {pagination?: Ref<Pagination>sorting?: Ref<Sorting>filters?: Ref<Partial<Filters>>
}) => {const isLoading = ref(false)const users = ref<UserData[]>([])const { filters = makeFiltersRef(), sorting = makeSortingRef(), pagination = makePaginationRef() } = options || {}const fetch = async () => {isLoading.value = trueconst result = await getUsers({...unref(filters),...unref(sorting),...unref(pagination),})if (result) {const { data, pagination: newPagination } = result;// Use 'data' and 'newPagination' here...users.value = dataignoreUpdates(() => {pagination.value = newPagination})} else {// Handle the case when 'result' is undefined}isLoading.value = false}const { ignoreUpdates } = watchIgnorable([pagination, sorting], fetch, { deep: true })watch(filters,() => {// Reset pagination to first page when filters changedpagination.value.page = 1fetch()},{ deep: true },)fetch()return {isLoading,filters,sorting,pagination,users,fetch,async add(user: UserData) {isLoading.value = trueawait UserApi.addUser(user)await fetch()isLoading.value = false},async update(user: UserData) {isLoading.value = trueawait UserApi.updateUser(user)await fetch()isLoading.value = false},async remove(id : number) {isLoading.value = trueawait UserApi.deleteUser(id)await fetch()isLoading.value = false},}
}

同时最下面除了导出所需要的一些对象,还导出了三个异步方法,在这三个方法中才调用axios异步与后端交互,当成功时候自然会重新调用fetch方法渲染数据,保持当前的结果一致性(使用isLoading来阻塞table,页面显示就是转圈圈正在加载中)到此基本就编写完成

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/17589.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统编程学习笔记

1 前言 1.1 环境 平台&#xff1a;uabntu20.04 工具&#xff1a;vim,gcc,make 1.2 GCC Linux系统下的GCC&#xff08;GNU Compiler Collection&#xff09;是GNU推出的功能强大、性能优越的多平台编译器&#xff0c;是GNU的代表作品之一。gcc是可以在多种硬体平台上编译出可执…

BIGO前端CICD平台

本文首发于&#xff1a;https://github.com/bigo-frontend/blog/ 欢迎关注、转载。 我是谁 BIGO前端CICD平台&#xff0c;是一个服务于前端团队的全研发周期管理平台&#xff0c;已经是我们团队日常都要使用的工具了。 该平台实现了一键创建项目、发布编排、新建迭代、checkl…

uniapp 使用vuex 在app上能获取到state,小程序获取不到

1. 在根目录下新建store目录, 在store目录下创建index.js定义状态值import Vue from vue; import Vuex from Vuex; import Vuex from vuex; Vue.use(Vuex);const store new Vuex.Store({ state: { login: false, token: , avatarUrl: , userName: }, mutations: { lo…

JavaWeb Servelt原理

Servlet简介: Servlet的主要工作&#xff1a;处理客户端请求&#xff0c;生成动态响应&#xff0c;通常用于扩展基于HTTP协议的Web服务器。 Servlet技术是Java EE规范的组成部分&#xff0c;代表了服务器端的Java程序&#xff0c;主要负责处理来自客户端的Web请求&#xff0c;…

国内信创web中间件生态

国内信创web中间件生态 东方通 官网https://www.tongtech.com/pctype/25.html 宝蓝德 官网https://www.bessystem.com/product/0ad9b8c4d6af462b8d15723a5f25a87d/info?p101 金蝶天燕 官网 https://www.apusic.com/list-117.html 中创 官网http://www.inforbus.com…

数据库数据恢复—空间不足导致sqlserver数据库连接失效的数据恢复案例

数据库数据恢复环境&#xff1a; 某品牌r520服务器&#xff0c;服务器中有7块SAS硬盘&#xff0c;这7块硬盘组建了一组2盘raid1阵列和一组5盘raid5阵列&#xff0c;raid1阵列存储空间安装操作系统&#xff0c;raid5阵列存储空间存放数据。服务器上部署sql server数据库&#xf…

野外作战武器操作3D模拟实操仿真训练以便老兵能适应不同的训练需求

强国必须强军&#xff0c;我国在军事方面的投入持续加大&#xff0c;自然在军事武器培训方面不容忽视&#xff0c;在军事领域&#xff0c;3D模拟展示不仅提升了军事训练的效率&#xff0c;还为我们提供了更加直观、真实的武器体验。 首先&#xff0c;3D军事武器模拟展示能够提供…

Nacos 2.x 系列【6】持久化

文章目录 1. 前言2. Derby3. Mysql3.1 初始化脚本3.2 服务端配置3.3 验证 4. 数据源插件 1. 前言 Nacos中的用户、租户、服务配置等信息&#xff0c;需要使用关系型数据库进行存储&#xff0c;在实际开发中&#xff0c;可能还会面临各种数据库适配问题。 2. Derby Derby是Ap…

Android Studio 中gradle的bin和all区别

1.在android studio中设置安装gradle时&#xff0c;真各种版本看到眼花缭乱&#xff0c;还有疑惑gradle-*.*-all.zip与gradle-*.*-bin.zip的区别是什么。下面解压如下: bin&#xff1a; all: 其实&#xff0c;用bin就可以了&#xff0c;all文件就是多了docs(文档)和src(源码)两…

Linux网络-Socket套接字_Windows与Linux端双平台基于Udp传输协议进行多线程跨平台的服务器与客户端网络通信的简易聊天室实现

文章目录 一、Socket套接字二、socket 常见API1. int socket(int domain, int type, int protocol);2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);struct sockaddr 3. ssize_t recvfrom(int socket, void *restrict buffer, size_t length…

go defer

type _defer struct {siz int32started boolopenDefer boolsp uintptrpc uintptrfn *funcval_panic *_paniclink *_defer }runtime._defer 结构体是延迟调用链表上的一个元素&#xff0c;所有的结构体都会通过 link 字段串联成链表。 只…

【全开源】酒店订单管理系统源码(FastAdmin+ThinkPHP)

一款基于FastAdminThinkPHP开发的旨在为民宿、酒店、宾馆等提供房态、订单、财务、客史等数据化、信息化的智慧管理工具&#xff0c;实现一站式订房管理&#xff0c;帮助酒店、民宿、宾馆提升管理效率&#xff0c;降低管理成本&#xff0c;提升行业竞争力。 打造高效、便捷的酒…

Generate Anything Anywhere in Any Scene #论文阅读

URL https://arxiv.org/pdf/2306.17154 TD;DR 2023 年 6 月 Wisconsin 的文章。围绕 ip 保持做的扩展任务&#xff0c;核心目标是对指定 ip 可以生成任意大小的&#xff08;指定 ip&#xff09;、任意背景的图片&#xff0c;同时可以通过 bbox 控制物体位置和多物体生成。主…

SOLIDWORKS教育版代理商应该如何选择?

SOLIDWORKS作为目前流行的三维设计软件在工程设计&#xff0c;制造和建筑中有着广泛的应用前景。教育版SOLIDWORKS软件是学生及教育机构学习教学的理想平台。 下面介绍几个挑选SOLIDWORKS教育版代理的关键要素: 1、专业知识与经验&#xff1a;代理商应掌握SOLIDWORKS等软件的丰…

ResNet残差网络的学习【概念+翻译】

基于何明凯前辈论文的学习 1.主要内容&#xff08;背景&#xff09; 1、首先提了一个base&#xff1a;神经网络的深度越深&#xff0c;越难以训练。 2、原因&#xff1a;因为随着神经网络层数的增加&#xff0c;通常会遇到梯度消失或梯度爆炸等问题&#xff0c;这会导致训练变…

gem5模拟器入门(三)——在配置脚本中添加Cache

使用gem5模拟器入门(二)——创建一个简单的配置脚本-CSDN博客配置脚本作为起点,本章将介绍一个更复杂的配置。我们将向系统添加一个缓存层次结构,如下图所示。此外,本章还将介绍如何理解gem5的统计输出,并向您的脚本添加命令行参数。 1.创建Cache对象 我们将使用经典的缓…

Robot Framework自动化测试基础入门

1、什么是Robot Framework Robot Framework是一个基于Python的关键字驱动的自动化测试框架。以下是关于Robot Framework的几个特点: 基于关键字驱动: 它允许测试人员使用Python封装关键字,这些关键字可以在非编码环境下被用来构建可执行的测试用例。易于扩展: 作为一个开源工…

20240528解决飞凌的OK3588-C的核心板的TYPE-C1接口识别问题

20240528解决飞凌的OK3588-C的核心板的TYPE-C1接口识别问题 2024/5/28 16:46 缘起&#xff1a; 现阶段碰到的USB相关的问题&#xff1a;&#xff08;LINUX R4版本&#xff09; 1、USB3.0插USB摄像头 lsusb找不到设备 2、刷机口只接了3根线&#xff0c;GND/D/D-&#xff0c;可以…

2024HBCPC:E Breakfast II

题目描述 作为一个合格的大学生&#xff0c;你不仅需要学习成绩好&#xff0c;还需要会买包子和鸡蛋。 今天&#xff0c;又轮到你们给你的导师买早饭了&#xff01; 这一次你们一共需要给导师买 n n n 个包子和 m m m 个鸡蛋&#xff08;请注意&#xff0c;这一次可能不再只…

搭贝财务管理助您轻松掌控财务大局

在当今竞争激烈的商业环境中&#xff0c;有效的财务管理是企业成功的关键之一。搭贝财务管理平台为您提供了一揽子解决方案&#xff0c;助您轻松掌握财务大局&#xff0c;实现财务管控的全面数字化。 &#x1f4c8; 基础信息管理 搭贝财务管理平台首先提供了完善的基础信息管理…