Browse Source

refactoring component :UserComponent

pull/109/head
cKey 5 years ago
parent
commit
5d060666b6
  1. BIN
      aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/event-bus-cap.db
  2. 171
      vueJs/src/api/abpconfiguration.ts
  3. 120
      vueJs/src/api/users.ts
  4. 7
      vueJs/src/components/PermissionForm/index.vue
  5. 12
      vueJs/src/lang/zh.ts
  6. 4
      vueJs/src/mixins/EventBusMiXin.ts
  7. 46
      vueJs/src/views/admin/roles/components/RoleEditForm.vue
  8. 32
      vueJs/src/views/admin/roles/index.vue
  9. 204
      vueJs/src/views/admin/users/components/UserCreateForm.vue
  10. 321
      vueJs/src/views/admin/users/components/UserCreateOrUpdateForm.vue
  11. 373
      vueJs/src/views/admin/users/components/UserEditForm.vue
  12. 183
      vueJs/src/views/admin/users/index.vue
  13. 396
      vueJs/src/views/example/components/ArticleDetail.vue
  14. 48
      vueJs/src/views/example/components/Dropdown/Comment.vue
  15. 51
      vueJs/src/views/example/components/Dropdown/Platform.vue
  16. 50
      vueJs/src/views/example/components/Dropdown/SourceUrl.vue
  17. 3
      vueJs/src/views/example/components/Dropdown/index.ts
  18. 18
      vueJs/src/views/example/components/Warning.vue
  19. 16
      vueJs/src/views/example/create.vue
  20. 16
      vueJs/src/views/example/edit.vue
  21. 158
      vueJs/src/views/example/list.vue

BIN
aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/event-bus-cap.db

Binary file not shown.

171
vueJs/src/api/abpconfiguration.ts

@ -18,19 +18,19 @@ export default class AbpConfigurationService {
/** 授权 */
export class Auth {
/** 权限集合 */
policies?: { [key: string]: boolean}
policies?: { [key: string]: boolean} = {}
/** 已授权集合 */
grantedPolicies?: { [key: string]: boolean}
grantedPolicies?: { [key: string]: boolean} = {}
}
/** 当前租户 */
export class CurrentTenant {
/** 标识 */
id?: string
id? = ''
/** 名称 */
name?: string
name? = ''
/** 是否可用 */
isAvailable!: boolean
isAvailable = false
public clear() {
this.id = ''
@ -42,101 +42,101 @@ export class CurrentTenant {
/** 当前用户 */
export class CurrentUser {
/** 标识 */
id?: string
id? = ''
/** 邮件地址 */
email?: string
email? = ''
/** 邮件已验证 */
emailVerified!: boolean
emailVerified = false
/** 手机号 */
phoneNumber?: string
phoneNumber? = ''
/** 手机号已验证 */
phoneNumberVerified!: boolean
phoneNumberVerified = false
/** 名称 */
name?: string
name? = ''
/** 简称 */
surName?: string
surName? = ''
/** 用户名 */
userName?: string
userName? = ''
/** 所属租户 */
tenantId?: string
tenantId? = ''
/** 是否已认证 */
isAuthenticated!: boolean
isAuthenticated = false
/** 所属角色列表 */
roles!: string[]
roles = new Array<string>()
}
/** 功能 */
export class Feature {
/** 功能集合 */
values?: { [key: string]: string}
values?: { [key: string]: string} = {}
}
/** 时区转换 */
export class DateTimeFormat {
/** 日历算法 */
calendarAlgorithmType!: string
calendarAlgorithmType = ''
/** 日期分隔符 */
dateSeparator!: string
dateSeparator = ''
/** 日期时间格式 */
dateTimeFormatLong!: string
dateTimeFormatLong = ''
/** 完整日期时间格式 */
fullDateTimePattern!: string
fullDateTimePattern = ''
/** 长时间格式 */
longTimePattern!: string
longTimePattern = ''
/** 短日期格式 */
shortDatePattern!: string
shortDatePattern = ''
/** 短时间格式 */
shortTimePattern!: string
shortTimePattern = ''
}
/** 当前区域信息 */
export class CurrentCulture {
/** 本地化名称 */
cultureName!: string
cultureName = ''
/** 显示名称 */
displayName!: string
displayName = ''
/** 英文名称 */
englishName!: string
englishName = ''
/** 是否从右到左 */
isRightToLeft!: boolean
isRightToLeft = false
/** 名称 */
name!: string
name = ''
/** 本地名称 */
nativeName!: string
nativeName = ''
/** 三个字母的ISO名称 */
threeLetterIsoLanguageName!: string
threeLetterIsoLanguageName = ''
/** 两个字母的ISO名称 */
twoLetterIsoLanguageName!: string
twoLetterIsoLanguageName = ''
/** 日期时间格式 */
dateTimeFormat!: DateTimeFormat
dateTimeFormat = new DateTimeFormat()
}
/** 语言 */
export class Language {
/** 本地化名称 */
cultureName!: string
cultureName = ''
/** 显示名称 */
displayName!: string
displayName = ''
/** 图标 */
flagIcon?: string
flagIcon = ''
/** 用户界面本地化名称 */
uiCultureName!: string
uiCultureName = ''
}
/** 本地化 */
export class Localization {
/** 当前区域 */
currentCulture!: CurrentCulture
currentCulture = new CurrentCulture()
/** 默认本地化资源名称 */
defaultResourceName?: string
defaultResourceName = ''
/** 支持的语言列表 */
languages!: Language[]
languages = new Array<Language>()
/** 本地化资源集合 */
values!: {[key: string]: {[key: string]: string}}
values: {[key: string]: {[key: string]: string}} = {}
/** 语言映射集合 */
languagesMap?: {[key: string]: INameValue<string>[]}
languagesMap: {[key: string]: INameValue<string>[]} = {}
/** 语言文档映射集合 */
languageFilesMap?: {[key: string]: INameValue<string>[]}
languageFilesMap: {[key: string]: INameValue<string>[]} = {}
}
/** 多租户配置 */
@ -148,7 +148,7 @@ export class MultiTenancy {
/** 全局设置 */
export class Setting {
/** 设置集合 */
values?: {[key: string]: any}
values: {[key: string]: any} = {}
}
/** 实体查询属性扩展 */
@ -166,11 +166,11 @@ export class ExtensionPropertyApiUpdate extends Available {
/** 实体属性api定义 */
export class ExtensionPropertyApi {
/** 查询时 */
onGet!: ExtensionPropertyApiGet
onGet = new ExtensionPropertyApiGet()
/** 创建时 */
onCreate!: ExtensionPropertyApiCreate
onCreate = new ExtensionPropertyApiCreate()
/** 更新时 */
onUpdate!: ExtensionPropertyApiUpdate
onUpdate = new ExtensionPropertyApiUpdate()
}
export class ExtensionPropertyUiTable extends Available {
@ -180,55 +180,55 @@ export class ExtensionPropertyUiForm extends Available {
}
export class ExtensionPropertyUi {
onTable!: ExtensionPropertyUiTable
onCreateForm!: ExtensionPropertyUiForm
onEditForm!: ExtensionPropertyUiForm
onTable = new ExtensionPropertyUiTable()
onCreateForm = new ExtensionPropertyUiForm()
onEditForm = new ExtensionPropertyUiForm()
}
export class LocalizableString {
name!: string
resource?: string
name = ''
resource = ''
}
export class ExtensionPropertyAttribute {
typeSimple?: string
config?: {[key: string]: any}
typeSimple = ''
config: {[key: string]: any} = {}
}
export class ExtensionProperty {
type!: string
typeSimple!: string
displayName?: LocalizableString
api!: ExtensionPropertyApi
ui!: ExtensionPropertyUi
attributes!: ExtensionPropertyAttribute[]
configuration!: {[key: string]: any}
defaultValue!: any
type = ''
typeSimple = ''
displayName = new LocalizableString()
api = new ExtensionPropertyApi()
ui = new ExtensionPropertyUi()
attributes = new Array<ExtensionPropertyAttribute>()
configuration: {[key: string]: any} = {}
defaultValue: any = ''
}
export class EntityExtension {
properties!: {[key: string]: ExtensionProperty}
configuration!: {[key: string]: any}
properties: {[key: string]: ExtensionProperty} = {}
configuration: {[key: string]: any} = {}
}
export class ModuleExtension {
entities!: {[key: string]: EntityExtension}
configuration!: {[key: string]: any}
entities: {[key: string]: EntityExtension} = {}
configuration: {[key: string]: any} = {}
}
export class ExtensionEnumField {
name!: string
value!: any
name = ''
value: any = ''
}
export class ExtensionEnum {
fields!: ExtensionEnumField[]
localizationResource!: string
fields = new Array<ExtensionEnumField>()
localizationResource = ''
}
export class ObjectExtension {
modules!: {[key: string]: ModuleExtension}
enums!: {[key: string]: ExtensionEnum}
modules: {[key: string]: ModuleExtension} = {}
enums: {[key: string]: ExtensionEnum} = {}
}
/** abp框架信息 */
@ -254,25 +254,14 @@ export interface IAbpConfiguration {
}
export class AbpConfiguration implements IAbpConfiguration {
auth!: Auth
currentTenant!: CurrentTenant
currentUser!: CurrentUser
features!: Feature
localization!: Localization
multiTenancy!: MultiTenancy
objectExtensions!: ObjectExtension
setting!: Setting
constructor() {
this.auth = new Auth()
this.setting = new Setting()
this.features = new Feature()
this.currentUser = new CurrentUser()
this.localization = new Localization()
this.multiTenancy = new MultiTenancy()
this.currentTenant = new CurrentTenant()
this.objectExtensions = new ObjectExtension()
}
auth = new Auth()
currentTenant = new CurrentTenant()
currentUser = new CurrentUser()
features = new Feature()
localization = new Localization()
multiTenancy = new MultiTenancy()
objectExtensions = new ObjectExtension()
setting = new Setting()
public getSetting(key: string) {
if (this.setting.values && this.setting.values[key]) {

120
vueJs/src/api/users.ts

@ -1,5 +1,5 @@
import qs from 'querystring'
import { PagedAndSortedResultRequestDto, FullAuditedEntityDto, PagedResultDto, ListResultDto } from '@/api/types'
import { PagedAndSortedResultRequestDto, FullAuditedEntityDto, PagedResultDto, ListResultDto, ExtensibleObject } from '@/api/types'
import { OrganizationUnit } from './organizationunit'
import ApiService from './serviceBase'
@ -17,25 +17,25 @@ export default class UserApiService {
if (input.filter) {
_url += '&filter=' + input.filter
}
return ApiService.Get<PagedResultDto<UserDataDto>>(_url, IdentityServiceUrl)
return ApiService.Get<PagedResultDto<User>>(_url, IdentityServiceUrl)
}
public static getUserById(userId: string) {
let _url = '/api/identity/users/'
_url += userId
return ApiService.Get<UserDataDto>(_url, IdentityServiceUrl)
return ApiService.Get<User>(_url, IdentityServiceUrl)
}
public static getUserByName(userName: string) {
let _url = '/api/identity/users/by-username/'
_url += userName
return ApiService.Get<UserDataDto>(_url, IdentityServiceUrl)
return ApiService.Get<User>(_url, IdentityServiceUrl)
}
public static updateUser(userId: string | undefined, userData: UserUpdateDto) {
public static updateUser(userId: string, userData: UserUpdate) {
let _url = '/api/identity/users/'
_url += userId
return ApiService.Put<UserDataDto>(_url, userData, IdentityServiceUrl)
return ApiService.Put<User>(_url, userData, IdentityServiceUrl)
}
public static deleteUser(userId: string | undefined) {
@ -44,9 +44,9 @@ export default class UserApiService {
return ApiService.Delete(_url, IdentityServiceUrl)
}
public static createUser(userData: UserCreateDto) {
public static createUser(userData: UserCreate) {
const _url = '/api/identity/users'
return ApiService.Post<UserDataDto>(_url, userData, IdentityServiceUrl)
return ApiService.Post<User>(_url, userData, IdentityServiceUrl)
}
public static getUserRoles(userId: string) {
@ -122,7 +122,7 @@ export default class UserApiService {
public static userRegister(registerData: UserRegisterData) {
const _url = '/api/account/phone/register'
return ApiService.HttpRequest<UserDataDto>({
return ApiService.HttpRequest<User>({
baseURL: IdentityServiceUrl,
url: _url,
method: 'POST',
@ -317,34 +317,6 @@ export class UserLoginResult {
refresh_token!: string
}
/** 创建用户对象 */
export class UserCreateDto {
/** 用户名 */
name!: string
/** 用户账户 */
userName!: string
/** 用户密码 */
password!: string
/** 用户简称 */
surname?: string
/** 邮件地址 */
email!: string
/** 联系方式 */
phoneNumber: number | undefined
/** 双因素验证 */
twoFactorEnabled!: boolean
/** 登录失败锁定 */
lockoutEnabled!: boolean
/** 用户列表 */
roleNames?: string[]
constructor() {
this.twoFactorEnabled = false
this.lockoutEnabled = true
this.roleNames = new Array<string>()
}
}
/** 用户密码变更对象 */
export class UserChangePasswordDto {
/** 当前密码 */
@ -375,68 +347,68 @@ export class UserRole implements IUserRole {
isStatic!: boolean
/** 是否公共角色 */
isPublic!: boolean
/** 并发令牌 */
concurrencyStamp: string | undefined
}
/** 变更用户对象 */
export class UserUpdateDto implements IUserData {
export class UserCreateOrUpdate extends ExtensibleObject {
/** 用户名 */
name!: string;
name = ''
/** 用户账户 */
userName!: string;
userName = ''
/** 用户简称 */
surname?: string;
surname = ''
/** 邮件地址 */
email!: string;
email = ''
/** 联系方式 */
phoneNumber?: number;
/** 双因素验证 */
twoFactorEnabled!: boolean;
phoneNumber = ''
/** 登录锁定 */
lockoutEnabled!: boolean;
lockoutEnabled = false
/** 角色列表 */
roleNames: string[] | null = null
/** 密码 */
password: string | null = null
}
/** 变更用户对象 */
export class UserUpdate extends UserCreateOrUpdate {
/** 并发令牌 */
concurrencyStamp!: string;
/** 用户角色列表 */
roles: string[]
concurrencyStamp = ''
}
constructor() {
this.roles = new Array<string>()
}
export class UserCreate extends UserCreateOrUpdate {
}
/** 用户对象 */
export class UserDataDto extends FullAuditedEntityDto implements IUserData {
export class User extends FullAuditedEntityDto implements IUser {
/** 用户名 */
name!: string
name = ''
/** 用户账户 */
userName!: string
userName = ''
/** 用户简称 */
surname!: string
surname = ''
/** 邮件地址 */
email!: string
email = ''
/** 联系方式 */
phoneNumber?: number
phoneNumber = ''
/** 双因素验证 */
twoFactorEnabled!: boolean
twoFactorEnabled = false
/** 登录锁定 */
lockoutEnabled!: boolean
/** 并发令牌 */
concurrencyStamp!: string
lockoutEnabled = false
/** 用户标识 */
id!: string
id = ''
/** 租户标识 */
tenentId: string | undefined
tenentId? = ''
/** 邮箱已验证 */
emailConfirmed!: boolean
emailConfirmed = false
/** 联系方式已验证 */
phoneNumberConfirmed!: boolean
phoneNumberConfirmed = false
/** 锁定截止时间 */
lockoutEnd: Date | undefined
lockoutEnd?: Date = undefined
/** 并发令牌 */
concurrencyStamp = ''
}
/** 用户对象接口 */
export interface IUserData {
export interface IUser {
/** 用户名 */
name: string
/** 用户账户 */
@ -446,13 +418,11 @@ export interface IUserData {
/** 邮件地址 */
email: string
/** 联系方式 */
phoneNumber?: number
phoneNumber?: string
/** 双因素验证 */
twoFactorEnabled: boolean
/** 登录锁定 */
lockoutEnabled: boolean
/** 锁定截止时间 */
concurrencyStamp: string | undefined
}
/** 用户角色接口 */
@ -467,8 +437,6 @@ export interface IUserRole {
isStatic: boolean
/** 公共角色 */
isPublic: boolean
/** 并发令牌 */
concurrencyStamp: string | undefined
}
export class ChangeUserOrganizationUnitDto {

7
vueJs/src/components/PermissionForm/index.vue

@ -21,6 +21,7 @@
</el-checkbox>
<el-divider />
<el-tabs
v-model="activeTabPane"
tab-position="left"
type="card"
>
@ -236,6 +237,8 @@ export default class PermissionForm extends Vue {
@Prop({ default: false })
private readonly!: boolean
/** 激活tab页 */
private activeTabPane = ''
/** 确认按钮忙碌状态 */
private confirmButtonBusy = false
/** 当前编辑权限实体名称 */
@ -350,6 +353,7 @@ export default class PermissionForm extends Vue {
* 获取权限集合
*/
private handleGetPermissions() {
this.activeTabPane = ''
this.permissionGroups.length = 0
if (this.showDialog && this.providerName) {
PermissionApiService.getPermissionsByKey(this.providerName, this.providerKey).then(res => {
@ -366,6 +370,9 @@ export default class PermissionForm extends Vue {
})
this.permissionGroups.push(group)
})
if (this.permissionGroups.length > 0) {
this.activeTabPane = this.permissionGroups[0].name
}
})
}
}

12
vueJs/src/lang/zh.ts

@ -654,5 +654,17 @@ export default {
uploadSuccess: '上传成功',
folderNameIsRequired: '目录名称不能为空',
folderCreateSuccess: '目录 {name} 已创建!'
},
AbpValidation: {
ThisFieldIsNotAValidEmailAddress: '字段不是有效的邮箱地址',
ThisFieldMustBeAStringWithAMinimumLengthOf: '字段必须是最小长度为{0}的字符串',
'ThisFieldMustBeAStringWithAMinimumLengthOf{0}AndAMaximumLengthOf{1}':'字段必须是最小长度为{0}并且最大长度{1}的字符串'
},
AbpIdentity: {
Lock: '锁定',
LockoutEnd: '锁定日期',
LockoutEnabled: '登录尝试失败后锁定帐户',
RoleList: '角色列表',
HasRoles: '已有角色'
}
}

4
vueJs/src/mixins/EventBusMiXin.ts

@ -44,8 +44,8 @@ export default class EventBusMiXin extends Vue {
* @param name
* @param callback
*/
protected unSubscribe(name: string, callback: (eventData: any) => void | undefined) {
this.$events.off(name, callback)
protected unSubscribe(name: string) {
this.$events.off(name, undefined)
}
/**

46
vueJs/src/views/admin/roles/components/RoleEditForm.vue

@ -41,19 +41,6 @@
@onOrganizationUnitsChanged="onOrganizationUnitsChanged"
/>
</el-tab-pane>
<el-tab-pane
v-if="rolePermissionLoaded"
:label="$t('roles.permission')"
name="permissions"
>
<permission-tree
ref="permissionTree"
:expanded="false"
:readonly="!checkPermission(['AbpIdentity.Roles.ManagePermissions'])"
:permission="rolePermission"
@onPermissionChanged="onPermissionChanged"
/>
</el-tab-pane>
</el-tabs>
<el-form-item>
<el-button
@ -77,20 +64,16 @@
</template>
<script lang="ts">
import { IPermission } from '@/api/types'
import { checkPermission } from '@/utils/permission'
import { Component, Prop, Watch, Vue } from 'vue-property-decorator'
import RoleService, { RoleDto, UpdateRoleDto } from '@/api/roles'
import PermissionTree from '@/components/PermissionTree/index.vue'
import OrganizationUnitTree from '@/components/OrganizationUnitTree/index.vue'
import PermissionService, { PermissionDto, UpdatePermissionsDto } from '@/api/permission'
import { ChangeUserOrganizationUnitDto } from '@/api/users'
import { Form } from 'element-ui'
@Component({
name: 'RoleEditForm',
components: {
PermissionTree,
OrganizationUnitTree
},
methods: {
@ -111,13 +94,6 @@ export default class extends Vue {
private roleOrganizationUnitChanged = false
private roleOrganizationUnits = new Array<string>()
/** 角色权限数据 */
private rolePermission = new PermissionDto()
/** 角色权限已变更 */
private rolePermissionChanged = false
/** 变更角色权限数据 */
private editRolePermissions = new Array<IPermission>()
private roleRules = {
name: [
{ required: true, message: this.l('global.pleaseInputBy', { key: this.l('roles.name') }), trigger: 'blur' },
@ -135,7 +111,6 @@ export default class extends Vue {
RoleService.getRoleById(this.roleId).then(role => {
this.role = role
this.handledGetRoleOrganizationUnits(role.id)
this.handleGetRolePermissions(role.name)
})
this.roleOrganizationUnitChanged = false
this.roleOrganizationUnits = new Array<string>()
@ -148,37 +123,20 @@ export default class extends Vue {
})
}
private handleGetRolePermissions(roleName: string) {
PermissionService.getPermissionsByKey('R', roleName).then(permission => {
this.rolePermission = permission
this.rolePermissionLoaded = true
})
}
private onOrganizationUnitsChanged(checkedKeys: string[]) {
this.roleOrganizationUnitChanged = true
this.roleOrganizationUnits = checkedKeys
}
private onPermissionChanged(permissions: IPermission[]) {
this.rolePermissionChanged = true
this.editRolePermissions = permissions
}
private onSave() {
const frmRole = this.$refs.formEditRole as any
frmRole.validate(async(valid: boolean) => {
const roleEditForm = this.$refs.roleEditForm as any
roleEditForm.validate(async(valid: boolean) => {
if (valid) {
const roleUpdateDto = new UpdateRoleDto()
roleUpdateDto.name = this.role.name
roleUpdateDto.isPublic = this.role.isPublic
roleUpdateDto.isDefault = this.role.isDefault
roleUpdateDto.concurrencyStamp = this.role.concurrencyStamp
if (this.rolePermissionChanged) {
const setRolePermissions = new UpdatePermissionsDto()
setRolePermissions.permissions = this.editRolePermissions
await PermissionService.setPermissionsByKey('R', this.rolePermission.entityDisplayName, setRolePermissions)
}
if (this.roleOrganizationUnitChanged) {
const roleOrganizationUnitDto = new ChangeUserOrganizationUnitDto()
roleOrganizationUnitDto.organizationUnitIds = this.roleOrganizationUnits

32
vueJs/src/views/admin/roles/index.vue

@ -120,6 +120,12 @@
>
{{ $t('AbpIdentity.ManageClaim') }}
</el-dropdown-item>
<el-dropdown-item
:command="{key: 'permission', row}"
:disabled="!checkPermission(['AbpIdentity.Roles.ManagePermissions'])"
>
{{ $t('AbpIdentity.Permissions') }}
</el-dropdown-item>
<el-dropdown-item
:command="row.isDefault ? {key: 'unDefault', row} : {key: 'default', row}"
:disabled="row.isStatic || !checkPermission(['AbpIdentity.Roles.Update'])"
@ -163,6 +169,14 @@
:role-id="editRoleId"
@closed="onClaimDialogClosed"
/>
<permission-form
provider-name="R"
:provider-key="editRoleName"
:readonly="!checkPermission(['AbpIdentity.Roles.ManagePermissions'])"
:show-dialog="showPermissionDialog"
@closed="onPermissionDialogClosed"
/>
</div>
</template>
@ -173,7 +187,7 @@ import Component, { mixins } from 'vue-class-component'
import RoleService, { RoleDto, UpdateRoleDto, RoleGetPagedDto } from '@/api/roles'
import { checkPermission } from '@/utils/permission'
import Pagination from '@/components/Pagination/index.vue'
import PermissionTree from '@/components/PermissionTree/index.vue'
import PermissionForm from '@/components/PermissionForm/index.vue'
import RoleEditForm from './components/RoleEditForm.vue'
import RoleCreateForm from './components/RoleCreateForm.vue'
import RoleClaimCreateOrUpdateForm from './components/RoleClaimCreateOrUpdateForm.vue'
@ -181,7 +195,7 @@ import RoleClaimCreateOrUpdateForm from './components/RoleClaimCreateOrUpdateFor
@Component({
name: 'RoleList',
components: {
PermissionTree,
PermissionForm,
Pagination,
RoleEditForm,
RoleCreateForm,
@ -196,6 +210,8 @@ export default class extends mixins(DataListMiXin) {
private editRoleId = ''
private showClaimDialog = false
private showCreateDialog = false
private editRoleName = ''
private showPermissionDialog = false
public dataFilter = new RoleGetPagedDto()
@ -218,6 +234,9 @@ export default class extends mixins(DataListMiXin) {
case 'claim' :
this.handleShowCliamDialog(command.row)
break
case 'permission' :
this.handleShowPermissionDialog(command.row)
break
case 'default' :
this.handleSetDefaultRole(command.row, true)
break
@ -246,6 +265,15 @@ export default class extends mixins(DataListMiXin) {
this.showClaimDialog = true
}
private handleShowPermissionDialog(row: RoleDto) {
this.editRoleName = row.name
this.showPermissionDialog = true
}
private onPermissionDialogClosed() {
this.showPermissionDialog = false
}
private onClaimDialogClosed() {
this.showClaimDialog = false
}

204
vueJs/src/views/admin/users/components/UserCreateForm.vue

@ -1,204 +0,0 @@
<template>
<el-form
ref="formCreateUser"
label-width="110px"
:model="createUser"
:rules="createUserRules"
>
<el-tabs v-model="activedTabPane">
<el-tab-pane
:label="$t('userProfile.basic')"
name="basic"
>
<el-form-item
prop="userName"
:label="$t('users.userName')"
>
<el-input
v-model="createUser.userName"
:placeholder="$t('userProfile.pleaseInputUserName')"
/>
</el-form-item>
<el-form-item
prop="name"
:label="$t('users.name')"
>
<el-input
v-model="createUser.name"
:placeholder="$t('userProfile.pleaseInputName')"
/>
</el-form-item>
<el-form-item
prop="surname"
:label="$t('users.surname')"
>
<el-input
v-model="createUser.surname"
:placeholder="$t('userProfile.pleaseInputSurname')"
/>
</el-form-item>
<el-form-item
prop="phoneNumber"
:label="$t('users.phoneNumber')"
>
<el-input
v-model="createUser.phoneNumber"
:placeholder="$t('userProfile.pleaseInputPhoneNumber')"
/>
</el-form-item>
<el-form-item
prop="email"
:label="$t('users.email')"
>
<el-input
v-model="createUser.email"
:placeholder="$t('userProfile.pleaseInputEmail')"
/>
</el-form-item>
</el-tab-pane>
<el-tab-pane
:label="$t('userProfile.security')"
name="security"
>
<el-form-item
prop="password"
label-width="100px"
:label="$t('userProfile.password')"
>
<el-input
v-model="createUser.password"
type="password"
:placeholder="$t('userProfile.pleaseInputPassword')"
/>
</el-form-item>
<el-form-item
prop="twoFactorEnabled"
label-width="100px"
:label="$t('users.twoFactorEnabled')"
>
<el-switch v-model="createUser.twoFactorEnabled" />
</el-form-item>
<el-form-item
prop="lockoutEnabled"
label-width="100px"
:label="$t('users.lockoutEnabled')"
>
<el-switch v-model="createUser.lockoutEnabled" />
</el-form-item>
</el-tab-pane>
</el-tabs>
<el-form-item>
<el-button
class="cancel"
style="width:100px"
@click="onCancel"
>
{{ $t('table.cancel') }}
</el-button>
<el-button
class="confirm"
type="primary"
style="width:100px"
@click="onSubmit"
>
{{ $t('table.confirm') }}
</el-button>
</el-form-item>
</el-form>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import UserApiService, { UserCreateDto } from '@/api/users'
import { checkPermission } from '@/utils/permission'
@Component({
name: 'UserProfile',
methods: {
checkPermission
}
})
export default class extends Vue {
private createUser: UserCreateDto
private activedTabPane: string
constructor() {
super()
this.activedTabPane = 'basic'
this.createUser = new UserCreateDto()
}
private validatePhoneNumberValue = (rule: any, value: string, callback: any) => {
const phoneReg = /^1[34578]\d{9}$/
if (!value || !phoneReg.test(value)) {
callback(new Error(this.l('global.pleaseInputBy', { key: this.l('global.correctPhoneNumber') })))
} else {
callback()
}
}
private createUserRules = {
userName: [
{ required: true, message: this.l('userProfile.pleaseInputUserName'), trigger: 'blur' },
{ min: 3, max: 128, message: this.l('global.charLengthRange', { min: 3, max: 128 }), trigger: 'blur' }
],
name: [
{ required: true, message: this.l('userProfile.pleaseInputName'), trigger: 'blur' },
{ min: 2, max: 256, message: this.l('global.charLengthRange', { min: 2, max: 256 }), trigger: 'blur' }
],
email: [
{ required: true, message: this.l('userProfile.pleaseInputEmail'), trigger: 'blur' },
{ type: 'email', message: this.l('global.pleaseInputBy', { key: this.l('global.correctEmailAddress') }), trigger: ['blur', 'change'] }
],
password: [
{ required: true, message: this.l('userProfile.pleaseInputPassword'), trigger: 'blur' },
{ min: 6, max: 15, message: this.l('global.charLengthRange', { min: 6, max: 15 }), trigger: 'blur' }
],
phoneNumber: [
{ required: true, validator: this.validatePhoneNumberValue, trigger: 'blur' }
]
}
private onSubmit() {
const frmCreateUser = this.$refs.formCreateUser as any
frmCreateUser.validate(async(valid: boolean) => {
if (valid) {
UserApiService.createUser(this.createUser).then(user => {
this.$message.success(this.l('users.createUserSuccess', { name: user.name }))
this.resetForm()
this.onCancel()
this.$emit('onUserProfileChanged', user.id)
})
}
})
}
private onCancel() {
this.resetForm()
this.$emit('onClose')
}
private resetForm() {
this.activedTabPane = 'basic'
this.createUser = new UserCreateDto()
const frmCreateUser = this.$refs.formCreateUser as any
frmCreateUser.resetFields()
}
private l(name: string, values?: any[] | { [key: string]: any }) {
return this.$t(name, values).toString()
}
}
</script>
<style lang="scss" scoped>
.confirm {
position: absolute;
right: 10px;
}
.cancel {
position: absolute;
right: 120px;
}
</style>

321
vueJs/src/views/admin/users/components/UserCreateOrUpdateForm.vue

@ -0,0 +1,321 @@
<template>
<el-dialog
:visible="showDialog"
:title="title"
width="800px"
custom-class="modal-form"
:close-on-click-modal="false"
:close-on-press-escape="false"
:show-close="false"
@close="onFormClosed"
>
<el-form
ref="editUserForm"
label-width="110px"
:model="currentUser"
:rules="currentUserRules"
>
<el-tabs v-model="activedTabPane">
<el-tab-pane
:label="$t('AbpIdentity.UserInformations')"
name="information"
>
<el-form-item
prop="userName"
:label="$t('AbpIdentity.DisplayName:UserName')"
>
<el-input
v-model="currentUser.userName"
:placeholder="$t('global.pleaseInputBy', {key: $t('AbpIdentity.DisplayName:UserName')})"
/>
</el-form-item>
<el-form-item
prop="name"
:label="$t('AbpIdentity.DisplayName:Name')"
>
<el-input
v-model="currentUser.name"
:placeholder="$t('global.pleaseInputBy', {key: $t('AbpIdentity.DisplayName:Name')})"
/>
</el-form-item>
<el-form-item
prop="surname"
:label="$t('AbpIdentity.DisplayName:Surname')"
>
<el-input
v-model="currentUser.surname"
:placeholder="$t('global.pleaseInputBy', {key: $t('AbpIdentity.DisplayName:Surname')})"
/>
</el-form-item>
<el-form-item
prop="phoneNumber"
:label="$t('AbpIdentity.DisplayName:PhoneNumber')"
>
<el-input
v-model="currentUser.phoneNumber"
:placeholder="$t('global.pleaseInputBy', {key: $t('AbpIdentity.DisplayName:PhoneNumber')})"
/>
</el-form-item>
<el-form-item
prop="email"
:label="$t('AbpIdentity.DisplayName:Email')"
>
<el-input
v-model="currentUser.email"
:placeholder="$t('global.pleaseInputBy', {key: $t('AbpIdentity.DisplayName:Email')})"
/>
</el-form-item>
<el-form-item
v-if="!isEditUser"
prop="password"
:label="$t('AbpIdentity.DisplayName:Password')"
>
<el-input
v-model="currentUser.password"
type="password"
:placeholder="$t('global.pleaseInputBy', {key: $t('AbpIdentity.DisplayName:Password')})"
/>
</el-form-item>
<el-row>
<el-col :span="8">
<el-form-item
prop="twoFactorEnabled"
label-width="120px"
:label="$t('AbpIdentity.DisplayName:TwoFactorEnabled')"
>
<el-switch v-model="currentUser.twoFactorEnabled" />
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item
prop="lockoutEnabled"
label-width="180px"
:label="$t('AbpIdentity.LockoutEnabled')"
>
<el-switch v-model="currentUser.lockoutEnabled" />
</el-form-item>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane
:label="$t('AbpIdentity.Roles')"
name="roles"
>
<el-transfer
v-model="currentUserRoles"
:titles="[$t('AbpIdentity.RoleList'),$t('AbpIdentity.HasRoles')]"
:data="roleList"
/>
</el-tab-pane>
</el-tabs>
<el-form-item>
<el-button
class="cancel"
type="info"
@click="onFormClosed"
>
{{ $t('AbpIdentity.Cancel') }}
</el-button>
<el-button
class="confirm"
type="primary"
icon="el-icon-check"
@click="onSave"
>
{{ $t('AbpIdentity.Save') }}
</el-button>
</el-form-item>
</el-form>
</el-dialog>
</template>
<script lang="ts">
import Component, { mixins } from 'vue-class-component'
import { Prop, Watch } from 'vue-property-decorator'
import { checkPermission } from '@/utils/permission'
import { AbpModule } from '@/store/modules/abp'
import EventBusMiXin from '@/mixins/EventBusMiXin'
import RoleService from '@/api/roles'
import { IRoleData } from '@/api/types'
import UserApiService, { UserCreate, UserUpdate, User, UserCreateOrUpdate } from '@/api/users'
@Component({
name: 'UserCreateOrUpdateForm',
methods: {
checkPermission
}
})
export default class extends mixins(EventBusMiXin) {
@Prop({ default: false })
private showDialog!: boolean
@Prop({ default: '' })
private editUserId!: string
private title = ''
private activedTabPane = 'information'
private editUser = new User()
private currentUser = new UserCreateOrUpdate()
private currentUserRoles = new Array<string>()
private roleList = new Array<{key: string, label: string, disabled: boolean}>()
private currentUserRoleChanged = false
private currentUserRules = {
userName: [
{ required: true, message: this.l('global.pleaseInputBy', { key: this.l('AbpIdentity.DisplayName:UserName') }), trigger: 'blur' }
],
email: [
{ required: true, message: this.l('global.pleaseInputBy', { key: this.l('AbpIdentity.DisplayName:Email') }), trigger: 'blur' },
{ type: 'email', message: this.l('AbpValidation.ThisFieldIsNotAValidEmailAddress'), trigger: ['blur', 'change'] }
],
password: [
{ required: true, message: this.l('global.pleaseInputBy', { key: this.l('AbpIdentity.DisplayName:Password') }), trigger: 'blur' },
{ min: this.requiredPasswordLength, message: this.l('AbpValidation.ThisFieldMustBeAStringWithAMinimumLengthOf', { 0: this.requiredPasswordLength }), trigger: 'blur' }
]
}
get requiredPasswordLength() {
if (AbpModule.configuration) {
const setting = AbpModule.configuration.setting.values['Abp.Identity.Password.RequiredLength']
if (setting) {
return Number(setting)
}
}
return 3
}
get isEditUser() {
if (this.editUserId) {
return true
}
return false
}
@Watch('showDialog', { immediate: true })
private onShowDialogChanged() {
this.handleGetUser()
if (this.editUserId) {
this.title = this.l('AbpIdentity.Edit')
} else {
this.title = this.l('AbpIdentity.NewUser')
}
}
@Watch('currentUserRoles')
onUserRolesChanged(val: string[], oldVal: string[]) {
if (val.length !== oldVal.length) {
this.currentUserRoleChanged = true
}
}
mounted() {
this.handleGetRoles()
}
private handleGetRoles() {
RoleService.getAllRoles().then(data => {
const roles = data.items.map((item: IRoleData) => {
return {
key: item.name,
label: item.name,
disabled: !item.isPublic
}
})
this.roleList = roles
})
}
private handleGetUser() {
this.activedTabPane = 'information'
this.editUser = new User()
this.currentUser = new UserCreateOrUpdate()
this.currentUserRoles = new Array<string>()
if (this.showDialog && this.editUserId) {
UserApiService.getUserById(this.editUserId).then(user => {
this.editUser = user
this.currentUser.name = user.name
this.currentUser.userName = user.userName
this.currentUser.surname = user.surname
this.currentUser.email = user.email
this.currentUser.phoneNumber = user.phoneNumber
this.currentUser.lockoutEnabled = user.lockoutEnabled
})
UserApiService.getUserRoles(this.editUserId).then(roles => {
this.currentUserRoles = roles.items.map(role => role.name)
})
}
}
private onSave() {
const editUserForm = this.$refs.editUserForm as any
editUserForm.validate(async(valid: boolean) => {
if (valid) {
if (this.isEditUser) {
const updateUser = new UserUpdate()
this.updateUserByInput(updateUser)
updateUser.concurrencyStamp = this.editUser.concurrencyStamp
updateUser.password = null
UserApiService.updateUser(this.editUserId, updateUser)
.then(user => {
this.trigger('userChanged', user)
this.onFormClosed()
})
} else {
const createUser = new UserCreate()
this.updateUserByInput(createUser)
createUser.password = this.currentUser.password
UserApiService.createUser(createUser)
.then(user => {
this.trigger('userChanged', user)
this.onFormClosed()
})
}
}
})
}
private updateUserByInput(user: UserCreateOrUpdate) {
user.name = this.currentUser.name
user.userName = this.currentUser.userName
user.surname = this.currentUser.surname
user.email = this.currentUser.email
user.phoneNumber = this.currentUser.phoneNumber
user.lockoutEnabled = this.currentUser.lockoutEnabled
if (this.currentUserRoleChanged) {
user.roleNames = this.currentUserRoles
} else {
user.roleNames = null
}
}
private onFormClosed() {
this.resetForm()
this.$emit('closed')
}
private resetForm() {
this.activedTabPane = 'infomation'
const editUserForm = this.$refs.editUserForm as any
editUserForm.resetFields()
}
private l(name: string, values?: any[] | { [key: string]: any }) {
return this.$t(name, values).toString()
}
}
</script>
<style lang="scss" scoped>
.confirm {
position: absolute;
right: 10px;
width: 100px
}
.cancel {
position: absolute;
right: 120px;
width: 100px
}
</style>

373
vueJs/src/views/admin/users/components/UserEditForm.vue

@ -1,373 +0,0 @@
<template>
<el-form
ref="formEditUser"
label-width="110px"
:model="userProfile"
:rules="userProfileRules"
>
<el-tabs v-model="activedTabPane">
<el-tab-pane
:label="$t('userProfile.basic')"
name="basic"
>
<el-form-item
prop="userName"
:label="$t('users.userName')"
>
<el-input
v-model="userProfile.userName"
:placeholder="$t('userProfile.pleaseInputUserName')"
/>
</el-form-item>
<el-form-item
prop="name"
:label="$t('users.name')"
>
<el-input
v-model="userProfile.name"
:placeholder="$t('userProfile.pleaseInputName')"
/>
</el-form-item>
<el-form-item
prop="surname"
:label="$t('users.surname')"
>
<el-input
v-model="userProfile.surname"
:placeholder="$t('userProfile.pleaseInputSurname')"
/>
</el-form-item>
<el-form-item
prop="phoneNumber"
:label="$t('users.phoneNumber')"
>
<el-input
v-model="userProfile.phoneNumber"
:placeholder="$t('userProfile.pleaseInputPhoneNumber')"
/>
</el-form-item>
<el-form-item
prop="email"
:label="$t('users.email')"
>
<el-input
v-model="userProfile.email"
:placeholder="$t('userProfile.pleaseInputEmail')"
/>
</el-form-item>
</el-tab-pane>
<el-tab-pane
:label="$t('userProfile.security')"
name="security"
>
<el-form-item
prop="twoFactorEnabled"
label-width="100px"
:label="$t('users.twoFactorEnabled')"
>
<el-switch v-model="userProfile.twoFactorEnabled" />
</el-form-item>
<el-form-item
prop="lockoutEnabled"
label-width="100px"
:label="$t('users.lockoutEnabled')"
>
<el-switch v-model="userProfile.lockoutEnabled" />
</el-form-item>
</el-tab-pane>
<el-tab-pane
:label="$t('userProfile.roles')"
name="roles"
>
<el-transfer
v-model="userRoles"
:titles="[$t('userProfile.roleList'),$t('userProfile.hasRoles')]"
:data="roleList"
/>
</el-tab-pane>
<el-tab-pane
:label="$t('userProfile.organizationUnits')"
>
<organization-unit-tree
:checked-organization-units="userOrganizationUnits"
@onOrganizationUnitsChanged="onOrganizationUnitsChanged"
/>
</el-tab-pane>
<el-tab-pane
v-if="allowedChangePermissions() && hasLoadPermission"
:label="$t('userProfile.permission')"
>
<PermissionTree
ref="permissionTree"
:expanded="false"
:readonly="!checkPermission(['AbpIdentity.Users.ManagePermissions'])"
:permission="userPermission"
@onPermissionChanged="onPermissionChanged"
/>
</el-tab-pane>
</el-tabs>
<el-form-item>
<el-button
class="cancel"
style="width:100px"
@click="onCancel"
>
{{ $t('table.cancel') }}
</el-button>
<el-button
class="confirm"
type="primary"
style="width:100px"
@click="onSubmit"
>
{{ $t('table.confirm') }}
</el-button>
</el-form-item>
</el-form>
</template>
<script lang="ts">
import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
import UserApiService, {
UserDataDto,
UserUpdateDto,
ChangeUserOrganizationUnitDto
} from '@/api/users'
import RoleService from '@/api/roles'
import PermissionService, { PermissionDto, UpdatePermissionsDto } from '@/api/permission'
import PermissionTree from '@/components/PermissionTree/index.vue'
import OrganizationUnitTree from '@/components/OrganizationUnitTree/index.vue'
import { IRoleData, IPermission } from '@/api/types'
import { checkPermission } from '@/utils/permission'
@Component({
name: 'UserProfile',
components: {
PermissionTree,
OrganizationUnitTree
},
methods: {
checkPermission
}
})
export default class extends Vue {
@Prop({ default: '' })
private userId!: string
private roleList = new Array<{key: string, label: string, disabled: boolean}>()
/** 用户组 */
private userRoles = new Array<string>()
private hasEditUser = false
private userRolesChanged = false
private userProfile = new UserDataDto()
/** 是否加载用户权限 */
private hasLoadPermission = false
/** 用户权限数据 */
private userPermission = new PermissionDto()
/** 用户权限已变更 */
private userPermissionChanged = false
/** 变更用户权限数据 */
private editUserPermissions = new Array<IPermission>()
/** 用户组织机构 */
private userOrganizationUnits = new Array<string>()
private userOrganizationUnitsChanged = false
private activedTabPane = 'basic'
@Watch('userId', { immediate: true })
onUserIdChanged(userId: string) {
if (userId) {
this.handleGetUserProfile()
}
}
onUserRolesChanged(val: string[], oldVal: string[]) {
if (val.length !== oldVal.length) {
this.userRolesChanged = true
}
}
onUserOrganizationUnitsChanged(val: string[], oldVal: string[]) {
if (val.length !== oldVal.length) {
this.userRolesChanged = true
}
}
onOrganizationUnitsChanged(checkedKeys: string[]) {
this.userOrganizationUnitsChanged = true
this.userOrganizationUnits = checkedKeys
}
private validatePhoneNumberValue = (rule: any, value: string, callback: any) => {
const phoneReg = /^1[34578]\d{9}$/
if (!value || !phoneReg.test(value)) {
callback(new Error(this.l('global.pleaseInputBy', { key: this.l('global.correctPhoneNumber') })))
} else {
callback()
}
}
private userProfileRules = {
userName: [
{ required: true, message: this.l('userProfile.pleaseInputUserName'), trigger: 'blur' },
{ min: 3, max: 20, message: this.l('global.charLengthRange', { min: 3, max: 20 }), trigger: 'blur' }
],
name: [
{ required: true, message: this.l('userProfile.pleaseInputName'), trigger: 'blur' },
{ min: 3, max: 50, message: this.l('global.charLengthRange', { min: 3, max: 50 }), trigger: 'blur' }
],
email: [
{ required: true, message: this.l('userProfile.pleaseInputEmail'), trigger: 'blur' },
{ type: 'email', message: this.l('global.pleaseInputBy', { key: this.l('global.correctEmailAddress') }), trigger: ['blur', 'change'] }
],
password: [
{ required: true, message: this.l('userProfile.pleaseInputPassword'), trigger: 'blur' },
{ min: 6, max: 15, message: this.l('global.charLengthRange', { min: 6, max: 15 }), trigger: 'blur' }
],
phoneNumber: [
{ required: true, validator: this.validatePhoneNumberValue, trigger: 'blur' }
]
}
mounted() {
this.handleGetRoles()
if (this.userId) {
this.handleGetUserProfile()
}
}
/** 允许变更权限 */
private allowedChangePermissions() {
return checkPermission(['AbpIdentity.Users.ManagePermissions'])
}
private handleGetUserProfile() {
this.userRoles = new Array<string>()
this.userPermission = new PermissionDto()
UserApiService.getUserById(this.userId).then(user => {
this.userProfile = user
this.handleGetUserRoles(this.userId)
this.handleGetUserOrganizationUnits(this.userId)
if (this.allowedChangePermissions()) {
this.handleGetUserPermissions(this.userId)
}
this.hasEditUser = true
})
}
private handleGetRoles() {
RoleService.getAllRoles().then(data => {
const roles = data.items.map((item: IRoleData) => {
return {
key: item.name,
label: item.name,
disabled: !item.isPublic
}
})
this.roleList = roles
})
}
private async handleGetUserRoles(userId: string) {
const userRoleDto = await UserApiService.getUserRoles(userId)
this.userRoles = userRoleDto.items.map(r => r.name)
//
this.$watch('userRoles', this.onUserRolesChanged)
}
private handleGetUserOrganizationUnits(userId: string) {
UserApiService.getUserOrganizationUnits(userId).then(res => {
this.userOrganizationUnits = res.items.map(ou => ou.id)
})
}
private async handleGetUserPermissions(id: string) {
PermissionService.getPermissionsByKey('U', id).then(permission => {
this.userPermission = permission
this.hasLoadPermission = true
})
}
private onPermissionChanged(permissions: IPermission[]) {
this.userPermissionChanged = true
this.editUserPermissions = permissions
}
private onSubmit() {
const frmEditUser = this.$refs.formEditUser as any
frmEditUser.validate(async(valid: boolean) => {
if (valid) {
const updateUserInput = this.createEditUserDto()
const user = await UserApiService.updateUser(this.userProfile.id, updateUserInput)
this.userProfile = user
this.$message.success(this.l('users.updateUserSuccess', { name: this.userProfile.name }))
if (this.userRolesChanged) {
await UserApiService.setUserRoles(this.userProfile.id, this.userRoles)
}
if (this.userOrganizationUnitsChanged) {
const changeUserOrganizationUnitDto = new ChangeUserOrganizationUnitDto()
changeUserOrganizationUnitDto.organizationUnitIds = this.userOrganizationUnits
await UserApiService.changeUserOrganizationUnits(this.userProfile.id, changeUserOrganizationUnitDto)
}
if (this.userPermissionChanged) {
const setUserPermissions = new UpdatePermissionsDto()
setUserPermissions.permissions = this.editUserPermissions
await PermissionService.setPermissionsByKey('U', this.userProfile.id, setUserPermissions)
}
frmEditUser.resetFields()
this.onCancel()
this.$emit('onUserProfileChanged', this.userProfile.id)
} else {
return false
}
})
}
private onCancel() {
this.resetForm()
this.$emit('onClose')
}
private resetForm() {
this.activedTabPane = 'basic'
this.userRoles = new Array<string>()
this.userOrganizationUnits = new Array<string>()
const frmEditUser = this.$refs.formEditUser as any
frmEditUser.resetFields()
if (this.hasLoadPermission) {
const userPermission = this.$refs.permissionTree as PermissionTree
userPermission.resetPermissions()
this.hasLoadPermission = false
}
}
private createEditUserDto() {
const updateUserInput = new UserUpdateDto()
updateUserInput.name = this.userProfile.name
updateUserInput.userName = this.userProfile.userName
updateUserInput.surname = this.userProfile.surname
updateUserInput.email = this.userProfile.email
updateUserInput.phoneNumber = this.userProfile.phoneNumber
updateUserInput.twoFactorEnabled = this.userProfile.twoFactorEnabled
updateUserInput.lockoutEnabled = this.userProfile.lockoutEnabled
updateUserInput.roles = this.userRoles
updateUserInput.concurrencyStamp = this.userProfile.concurrencyStamp
return updateUserInput
}
private l(name: string, values?: any[] | { [key: string]: any }) {
return this.$t(name, values).toString()
}
}
</script>
<style lang="scss" scoped>
.confirm {
position: absolute;
right: 10px;
}
.cancel {
position: absolute;
right: 120px;
}
</style>

183
vueJs/src/views/admin/users/index.vue

@ -17,15 +17,15 @@
type="primary"
@click="refreshPagedData"
>
{{ $t('users.searchList') }}
{{ $t('AbpIdentity.Search') }}
</el-button>
<el-button
class="filter-item"
type="primary"
:disabled="!checkPermission(['AbpIdentity.Users.Create'])"
@click="handleCreateUser"
@click="handleShowUserDialog('')"
>
{{ $t('users.createUser') }}
{{ $t('AbpIdentity.NewUser') }}
</el-button>
</div>
@ -40,7 +40,7 @@
@sort-change="handleSortChange"
>
<el-table-column
:label="$t('users.userName')"
:label="$t('AbpIdentity.DisplayName:UserName')"
prop="userName"
sortable
width="110px"
@ -51,7 +51,17 @@
</template>
</el-table-column>
<el-table-column
:label="$t('users.name')"
:label="$t('AbpIdentity.DisplayName:Surname')"
prop="surname"
width="110px"
align="center"
>
<template slot-scope="{row}">
<span>{{ row.surname }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('AbpIdentity.DisplayName:Name')"
prop="name"
width="110px"
align="center"
@ -61,7 +71,7 @@
</template>
</el-table-column>
<el-table-column
:label="$t('users.email')"
:label="$t('AbpIdentity.DisplayName:Email')"
prop="email"
sortable
min-width="180"
@ -72,7 +82,7 @@
</template>
</el-table-column>
<el-table-column
:label="$t('users.phoneNumber')"
:label="$t('AbpIdentity.DisplayName:PhoneNumber')"
prop="phoneNumber"
width="140px"
align="center"
@ -82,7 +92,7 @@
</template>
</el-table-column>
<el-table-column
:label="$t('users.lockoutEnd')"
:label="$t('AbpIdentity.LockoutEnd')"
prop="lockoutEnd"
sortable
width="140px"
@ -93,7 +103,7 @@
</template>
</el-table-column>
<el-table-column
:label="$t('users.creationTime')"
:label="$t('AbpIdentity.CreationTime')"
prop="creationTime"
sortable
width="140px"
@ -104,20 +114,12 @@
</template>
</el-table-column>
<el-table-column
:label="$t('users.operaActions')"
:label="$t('AbpIdentity.Actions')"
align="center"
width="250px"
min-width="250px"
width="120px"
fixed="right"
>
<template slot-scope="{row}">
<el-button
:disabled="!checkPermission(['AbpIdentity.Users.Update'])"
size="mini"
type="primary"
@click="handleShowEditUserForm(row)"
>
{{ $t('users.updateUser') }}
</el-button>
<el-dropdown
class="options"
@command="handleCommand"
@ -125,29 +127,41 @@
<el-button
v-permission="['AbpIdentity.Users']"
size="mini"
type="info"
type="primary"
>
{{ $t('users.otherOpera') }}<i class="el-icon-arrow-down el-icon--right" />
{{ $t('AbpIdentity.Actions') }}<i class="el-icon-arrow-down el-icon--right" />
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
:command="{key: 'edit', row}"
:disabled="!checkPermission(['AbpIdentity.Users.Update'])"
>
{{ $t('AbpIdentity.Edit') }}
</el-dropdown-item>
<el-dropdown-item
:command="{key: 'claim', row}"
:disabled="!checkPermission(['AbpIdentity.Users.ManageClaims'])"
>
{{ $t('AbpIdentity.ManageClaim') }}
</el-dropdown-item>
<el-dropdown-item
:command="{key: 'permission', row}"
:disabled="!checkPermission(['AbpIdentity.Users.ManagePermissions'])"
>
{{ $t('AbpIdentity.Permissions') }}
</el-dropdown-item>
<el-dropdown-item
:command="{key: 'lock', row}"
:disabled="!checkPermission(['AbpIdentity.Users.Update'])"
>
{{ $t('users.lockUser') }}
{{ $t('AbpIdentity.Lock') }}
</el-dropdown-item>
<el-dropdown-item
divided
:command="{key: 'delete', row}"
:disabled="!checkPermission(['AbpIdentity.Users.Delete'])"
>
{{ $t('users.deleteUser') }}
{{ $t('AbpIdentity.Delete') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
@ -155,7 +169,7 @@
</el-table-column>
</el-table>
<Pagination
<pagination
v-show="dataTotal>0"
:total="dataTotal"
:page.sync="currentPage"
@ -163,56 +177,47 @@
@pagination="refreshPagedData"
/>
<el-dialog
:visible.sync="showEditUserDialog"
custom-class="profile"
:title="$t('users.updateUserBy', {name: editUser.name})"
:show-close="false"
>
<UserEditForm
:user-id="editUser.id"
@onClose="handleCloseUserProfile"
@onUserProfileChanged="handleUserProfileChanged"
/>
</el-dialog>
<el-dialog
:visible.sync="showCreateUserDialog"
custom-class="profile"
:title="$t('users.createUser')"
:show-close="false"
>
<UserCreateForm
@onClose="handleCloseUserProfile"
@onUserProfileChanged="handleUserProfileChanged"
/>
</el-dialog>
<user-create-or-update-form
:show-dialog="showUserDialog"
:edit-user-id="editUserId"
@closed="onUserDialogClosed"
/>
<user-claim-create-or-update-form
:show-dialog="showClaimDialog"
:user-id="editUser.id"
:user-id="editUserId"
@closed="onClaimDialogClosed"
/>
<permission-form
provider-name="U"
:provider-key="editUserId"
:readonly="!allowedEditPermission"
:show-dialog="showPermissionDialog"
@closed="onPermissionDialogClosed"
/>
</div>
</template>
<script lang="ts">
import { UserModule } from '@/store/modules/user'
import DataListMiXin from '@/mixins/DataListMiXin'
import EventBusMiXin from '@/mixins/EventBusMiXin'
import Component, { mixins } from 'vue-class-component'
import UserApiService, { User, UsersGetPagedDto } from '@/api/users'
import Pagination from '@/components/Pagination/index.vue'
import { dateFormat, abpPagerFormat } from '@/utils'
import UserApiService, { UserDataDto, UsersGetPagedDto } from '@/api/users'
import UserCreateForm from './components/UserCreateForm.vue'
import UserEditForm from './components/UserEditForm.vue'
import PermissionForm from '@/components/PermissionForm/index.vue'
import UserCreateOrUpdateForm from './components/UserCreateOrUpdateForm.vue'
import UserClaimCreateOrUpdateForm from './components/UserClaimCreateOrUpdateForm.vue'
import { dateFormat, abpPagerFormat } from '@/utils'
import { checkPermission } from '@/utils/permission'
@Component({
name: 'UserList',
components: {
Pagination,
UserEditForm,
UserCreateForm,
PermissionForm,
UserCreateOrUpdateForm,
UserClaimCreateOrUpdateForm
},
filters: {
@ -225,18 +230,26 @@ import { checkPermission } from '@/utils/permission'
checkPermission
}
})
export default class extends mixins(DataListMiXin) {
/** 当前编辑用户 */
private editUser = new UserDataDto()
export default class extends mixins(DataListMiXin, EventBusMiXin) {
private editUserId = ''
public dataFilter = new UsersGetPagedDto()
private showCreateUserDialog = false
private showEditUserDialog = false
private showUserDialog = false
private showClaimDialog = false
private showPermissionDialog = false
get allowedEditPermission() {
return this.editUserId !== UserModule.id && checkPermission(['AbpIdentity.Users.ManagePermissions'])
}
mounted() {
this.refreshPagedData()
this.subscribe('userChanged', () => this.refreshPagedData())
}
destroyed() {
this.unSubscribe('userChanged')
}
protected processDataFilter() {
@ -255,41 +268,49 @@ export default class extends mixins(DataListMiXin) {
console.log('handleLockUser' + row.id)
}
private handleShowEditUserForm(row: UserDataDto) {
this.editUser = row
this.showEditUserDialog = true
private handleUserProfileChanged() {
this.refreshPagedData()
}
private handleCloseUserProfile() {
this.editUser = new UserDataDto()
this.showCreateUserDialog = false
this.showEditUserDialog = false
private handleShowCliamDialog(row: User) {
this.editUserId = row.id
this.showClaimDialog = true
}
private handleUserProfileChanged() {
this.refreshPagedData()
private onClaimDialogClosed() {
this.showClaimDialog = false
}
private handleCreateUser() {
this.editUser = new UserDataDto()
this.showCreateUserDialog = true
private handleShowPermissionDialog(id: string) {
this.editUserId = id
this.showPermissionDialog = true
}
private handleShowCliamDialog(row: UserDataDto) {
this.editUser = row
this.showClaimDialog = true
private onPermissionDialogClosed() {
this.showPermissionDialog = false
}
private onClaimDialogClosed() {
this.showClaimDialog = false
private handleShowUserDialog(id: string) {
this.editUserId = id
this.showUserDialog = true
}
private onUserDialogClosed() {
this.showUserDialog = false
}
/** 响应更多操作命令 */
private handleCommand(command: any) {
switch (command.key) {
case 'edit' :
this.handleShowUserDialog(command.row.id)
break
case 'claim' :
this.handleShowCliamDialog(command.row)
break
case 'permission' :
this.handleShowPermissionDialog(command.row.id)
break
case 'lock' :
this.handleLockUser(command.row)
break
@ -302,12 +323,12 @@ export default class extends mixins(DataListMiXin) {
/** 响应删除用户事件 */
private handleDeleteUser(row: any) {
this.$confirm(this.$t('users.delNotRecoverData').toString(),
this.$t('users.whetherDeleteUser', { name: row.userName }).toString(), {
this.$confirm(this.$t('AbpIdentity.UserDeletionConfirmationMessage', { 0: row.userName }).toString(),
this.$t('AbpIdentity.AreYouSure').toString(), {
callback: (action) => {
if (action === 'confirm') {
UserApiService.deleteUser(row.id).then(() => {
this.$message.success(this.$t('users.userHasBeenDeleted', { name: row.userName }).toString())
this.$message.success(this.$t('global.successful').toString())
this.refreshPagedData()
})
}

396
vueJs/src/views/example/components/ArticleDetail.vue

@ -1,396 +0,0 @@
<template>
<div class="createPost-container">
<el-form
ref="postForm"
:model="postForm"
:rules="rules"
class="form-container"
>
<sticky
:z-index="10"
:class-name="'sub-navbar '+postForm.status"
>
<comment-dropdown v-model="postForm.disableComment" />
<platform-dropdown v-model="postForm.platforms" />
<source-url-dropdown v-model="postForm.sourceURL" />
<el-button
v-loading="loading"
style="margin-left: 10px;"
type="success"
@click="submitForm"
>
Publish
</el-button>
<el-button
v-loading="loading"
type="warning"
@click="draftForm"
>
Draft
</el-button>
</sticky>
<div class="createPost-main-container">
<el-row>
<warning />
<el-col :span="24">
<el-form-item
style="margin-bottom: 40px;"
prop="title"
>
<material-input
v-model="postForm.title"
:maxlength="100"
name="name"
required
>
Title
</material-input>
</el-form-item>
<div class="postInfo-container">
<el-row>
<el-col :span="8">
<el-form-item
label-width="60px"
label="Author:"
class="postInfo-container-item"
>
<el-select
v-model="postForm.author"
:remote-method="getRemoteUserList"
filterable
default-first-option
remote
placeholder="Search user"
>
<el-option
v-for="(item, index) in userListOptions"
:key="item+index"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item
label-width="120px"
label="Publish Time:"
class="postInfo-container-item"
>
<el-date-picker
v-model="timestamp"
type="datetime"
format="yyyy-MM-dd HH:mm:ss"
placeholder="Select date and time"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item
label-width="90px"
label="Importance:"
class="postInfo-container-item"
>
<el-rate
v-model="postForm.importance"
:max="3"
:colors="['#99A9BF', '#F7BA2A', '#FF9900']"
:low-threshold="1"
:high-threshold="3"
style="display:inline-block"
/>
</el-form-item>
</el-col>
</el-row>
</div>
</el-col>
</el-row>
<el-form-item
style="margin-bottom: 40px;"
label-width="70px"
label="Summary:"
>
<el-input
v-model="postForm.abstractContent"
:rows="1"
type="textarea"
class="article-textarea"
autosize
placeholder="Please enter the content"
/>
<span
v-show="abstractContentLength"
class="word-counter"
>{{ abstractContentLength }}words</span>
</el-form-item>
<el-form-item
prop="content"
style="margin-bottom: 30px;"
>
<tinymce
v-if="tinymceActive"
ref="editor"
v-model="postForm.fullContent"
:height="400"
/>
</el-form-item>
<el-form-item
prop="imageURL"
style="margin-bottom: 30px;"
>
<upload-image v-model="postForm.imageURL" />
</el-form-item>
</div>
</el-form>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
import { isValidURL } from '@/utils/validate'
import { getArticle, defaultArticleData } from '@/api/articles'
import UserApiService, { UsersGetPagedDto, UserDataDto } from '@/api/users'
import { AppModule } from '@/store/modules/app'
import { TagsViewModule, ITagView } from '@/store/modules/tags-view'
import MaterialInput from '@/components/MaterialInput/index.vue'
import Sticky from '@/components/Sticky/index.vue'
import Tinymce from '@/components/Tinymce/index.vue'
import UploadImage from '@/components/UploadImage/index.vue'
import Warning from './Warning.vue'
import { CommentDropdown, PlatformDropdown, SourceUrlDropdown } from './Dropdown'
import { Form } from 'element-ui'
@Component({
name: 'ArticleDetail',
components: {
CommentDropdown,
PlatformDropdown,
SourceUrlDropdown,
MaterialInput,
Sticky,
Tinymce,
UploadImage,
Warning
}
})
export default class extends Vue {
@Prop({ default: false }) private isEdit!: boolean
private userApiService: UserApiService
constructor() {
super()
this.userApiService = new UserApiService()
}
private validateRequire = (rule: any, value: string, callback: Function) => {
if (value === '') {
if (rule.field === 'imageURL') {
this.$message({
message: 'Upload cover image is required',
type: 'error'
})
} else {
this.$message({
message: rule.field + ' is required',
type: 'error'
})
}
callback(new Error(rule.field + ' is required'))
} else {
callback()
}
}
private validateSourceUrl = (rule: any, value: string, callback: any) => {
if (value) {
if (isValidURL(value)) {
callback()
} else {
this.$message({
message: 'Invalid URL',
type: 'error'
})
callback(new Error('Invalid URL'))
}
} else {
callback()
}
}
private postForm = Object.assign({}, defaultArticleData)
private loading = false
private userListOptions = new Array<string>()
private rules = {
imageURL: [{ validator: this.validateRequire }],
title: [{ validator: this.validateRequire }],
fullContent: [{ validator: this.validateRequire }],
sourceURL: [{ validator: this.validateSourceUrl, trigger: 'blur' }]
}
private tempTagView?: ITagView
private tinymceActive = true
get abstractContentLength() {
return this.postForm.abstractContent.length
}
get lang() {
return AppModule.language
}
// set and get is useful when the data
// returned by the backend api is different from the frontend
// e.g.: backend return => "2013-06-25 06:59:25"
// frontend need timestamp => 1372114765000
get timestamp() {
return (+new Date(this.postForm.timestamp))
}
set timestamp(value) {
this.postForm.timestamp = +new Date(value)
}
created() {
if (this.isEdit) {
const id = this.$route.params && this.$route.params.id
this.fetchData(parseInt(id))
}
// Why need to make a copy of this.$route here?
// Because if you enter this page and quickly switch tag, may be in the execution of this.setTagsViewTitle function, this.$route is no longer pointing to the current page
// https://github.com/PanJiaChen/vue-element-admin/issues/1221
this.tempTagView = Object.assign({}, this.$route)
}
deactivated() {
this.tinymceActive = false
}
activated() {
this.tinymceActive = true
}
private async fetchData(id: number) {
try {
const { data } = await getArticle(id, { /* Your params here */ })
this.postForm = data.article
// Just for test
this.postForm.title += ` Article Id:${this.postForm.id}`
this.postForm.abstractContent += ` Article Id:${this.postForm.id}`
const title = this.lang === 'zh' ? '编辑文章' : 'Edit Article'
// Set tagsview title
this.setTagsViewTitle(title)
// Set page title
this.setPageTitle(title)
} catch (err) {
console.error(err)
}
}
private setTagsViewTitle(title: string) {
const tagView = this.tempTagView
if (tagView) {
tagView.title = `${title}-${this.postForm.id}`
TagsViewModule.updateVisitedView(tagView)
}
}
private setPageTitle(title: string) {
document.title = `${title} - ${this.postForm.id}`
}
private submitForm() {
(this.$refs.postForm as Form).validate(valid => {
if (valid) {
this.loading = true
this.$notify({
title: 'Success',
message: 'The post published successfully',
type: 'success',
duration: 2000
})
this.postForm.status = 'published'
// Just to simulate the time of the request
setTimeout(() => {
this.loading = false
}, 0.5 * 1000)
} else {
console.error('Submit Error!')
return false
}
})
}
private draftForm() {
if (this.postForm.fullContent.length === 0 || this.postForm.title.length === 0) {
this.$message({
message: 'Title and detail content are required',
type: 'warning'
})
return
}
this.$message({
message: 'The draft saved successfully',
type: 'success',
showClose: true,
duration: 1000
})
this.postForm.status = 'draft'
}
private async getRemoteUserList(name: string) {
const getUsersData = new UsersGetPagedDto()
getUsersData.filter = name
UserApiService.getUsers(getUsersData).then(res => {
if (!res.items) return
this.userListOptions = res.items.map((v: UserDataDto) => v.name)
})
}
}
</script>
<style lang="scss">
.article-textarea {
textarea {
padding-right: 40px;
resize: none;
border: none;
border-radius: 0px;
border-bottom: 1px solid #bfcbd9;
}
}
</style>
<style lang="scss" scoped>
.createPost-container {
position: relative;
.createPost-main-container {
padding: 40px 45px 20px 50px;
.postInfo-container {
position: relative;
@include clearfix;
margin-bottom: 10px;
.postInfo-container-item {
float: left;
}
}
}
.word-counter {
width: 40px;
position: absolute;
right: 10px;
top: 0px;
}
}
</style>

48
vueJs/src/views/example/components/Dropdown/Comment.vue

@ -1,48 +0,0 @@
<template>
<el-dropdown
:show-timeout="100"
trigger="click"
>
<el-button plain>
{{ !disableComment?'Comment: opened':'Comment: closed' }}
<i class="el-icon-caret-bottom el-icon--right" />
</el-button>
<el-dropdown-menu
slot="dropdown"
class="no-padding"
>
<el-dropdown-item>
<el-radio-group
v-model="disableComment"
style="padding: 10px;"
>
<el-radio :label="true">
Close comment
</el-radio>
<el-radio :label="false">
Open comment
</el-radio>
</el-radio-group>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
@Component({
name: 'CommentDropdown'
})
export default class extends Vue {
@Prop({ required: true }) private value!: boolean
get disableComment() {
return this.value
}
set disableComment(value) {
this.$emit('input', value)
}
}
</script>

51
vueJs/src/views/example/components/Dropdown/Platform.vue

@ -1,51 +0,0 @@
<template>
<el-dropdown
:hide-on-click="false"
:show-timeout="100"
trigger="click"
>
<el-button plain>
Platfroms({{ platforms.length }})
<i class="el-icon-caret-bottom el-icon--right" />
</el-button>
<el-dropdown-menu slot="dropdown">
<el-checkbox-group
v-model="platforms"
style="padding: 5px 15px;"
>
<el-checkbox
v-for="item in platformsOptions"
:key="item.key"
:label="item.key"
>
{{ item.name }}
</el-checkbox>
</el-checkbox-group>
</el-dropdown-menu>
</el-dropdown>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
@Component({
name: 'PlatformDropdown'
})
export default class extends Vue {
@Prop({ required: true }) private value!: string[]
private platformsOptions = [
{ key: 'a-platform', name: 'a-platform' },
{ key: 'b-platform', name: 'b-platform' },
{ key: 'c-platform', name: 'c-platform' }
]
get platforms() {
return this.value
}
set platforms(value) {
this.$emit('input', value)
}
}
</script>

50
vueJs/src/views/example/components/Dropdown/SourceUrl.vue

@ -1,50 +0,0 @@
<template>
<el-dropdown
:show-timeout="100"
trigger="click"
>
<el-button plain>
Link
<i class="el-icon-caret-bottom el-icon--right" />
</el-button>
<el-dropdown-menu
slot="dropdown"
class="no-padding"
style="width:400px"
>
<el-form-item
label-width="0px"
style="margin-bottom: 0px"
prop="sourceURL"
>
<el-input
v-model="sourceURL"
placeholder="Please enter the content"
>
<template slot="prepend">
URL
</template>
</el-input>
</el-form-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
@Component({
name: 'SourceUrlDropdown'
})
export default class extends Vue {
@Prop({ required: true }) private value!: string
get sourceURL() {
return this.value
}
set sourceURL(value) {
this.$emit('input', value)
}
}
</script>

3
vueJs/src/views/example/components/Dropdown/index.ts

@ -1,3 +0,0 @@
export { default as CommentDropdown } from './Comment.vue'
export { default as PlatformDropdown } from './Platform.vue'
export { default as SourceUrlDropdown } from './SourceUrl.vue'

18
vueJs/src/views/example/components/Warning.vue

@ -1,18 +0,0 @@
<template>
<aside>
{{ $t('example.warning') }}
<a
href="https://armour.github.io/vue-typescript-admin-docs/guide/essentials/tags-view.html"
target="_blank"
>Document</a>
</aside>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component({
name: 'Warning'
})
export default class extends Vue {}
</script>

16
vueJs/src/views/example/create.vue

@ -1,16 +0,0 @@
<template>
<article-detail :is-edit="false" />
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import ArticleDetail from './components/ArticleDetail.vue'
@Component({
name: 'CreateArticle',
components: {
ArticleDetail
}
})
export default class extends Vue {}
</script>

16
vueJs/src/views/example/edit.vue

@ -1,16 +0,0 @@
<template>
<article-detail :is-edit="true" />
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import ArticleDetail from './components/ArticleDetail.vue'
@Component({
name: 'EditArticle',
components: {
ArticleDetail
}
})
export default class extends Vue {}
</script>

158
vueJs/src/views/example/list.vue

@ -1,158 +0,0 @@
<template>
<div class="app-container">
<el-table
v-loading="listLoading"
:data="list"
border
fit
highlight-current-row
style="width: 100%"
>
<el-table-column
width="80"
align="center"
label="ID"
>
<template slot-scope="scope">
<span>{{ scope.row.id }}</span>
</template>
</el-table-column>
<el-table-column
width="180px"
align="center"
label="Date"
>
<template slot-scope="scope">
<span>{{ scope.row.timestamp | parseTime }}</span>
</template>
</el-table-column>
<el-table-column
width="180px"
align="center"
label="Author"
>
<template slot-scope="scope">
<span>{{ scope.row.author }}</span>
</template>
</el-table-column>
<el-table-column
width="105px"
label="Importance"
>
<template slot-scope="scope">
<svg-icon
v-for="n in +scope.row.importance"
:key="n"
name="star"
class="meta-item__icon"
/>
</template>
</el-table-column>
<el-table-column
class-name="status-col"
label="Status"
width="110"
>
<template slot-scope="{row}">
<el-tag :type="row.status | articleStatusFilter">
{{ row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column
min-width="300px"
label="Title"
>
<template slot-scope="{row}">
<router-link
:to="'/example/edit/'+row.id"
class="link-type"
>
<span>{{ row.title }}</span>
</router-link>
</template>
</el-table-column>
<el-table-column
align="center"
label="Actions"
width="120"
>
<template slot-scope="scope">
<router-link :to="'/example/edit/'+scope.row.id">
<el-button
type="primary"
size="small"
icon="el-icon-edit"
>
Edit
</el-button>
</router-link>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="listQuery.page"
:limit.sync="listQuery.limit"
@pagination="getList"
/>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import { getArticles } from '@/api/articles'
import { IArticleData } from '@/api/types'
import Pagination from '@/components/Pagination/index.vue'
@Component({
name: 'ArticleList',
components: {
Pagination
}
})
export default class extends Vue {
private total = 0
private list: IArticleData[] = []
private listLoading = true
private listQuery = {
page: 1,
limit: 20
}
created() {
this.getList()
}
private async getList() {
this.listLoading = true
const { data } = await getArticles(this.listQuery)
this.list = data.items
this.total = data.total
// Just to simulate the time of the request
setTimeout(() => {
this.listLoading = false
}, 0.5 * 1000)
}
}
</script>
<style lang="scss" scoped>
.edit-input {
padding-right: 100px;
}
.cancel-btn {
position: absolute;
right: 15px;
top: 10px;
}
</style>
Loading…
Cancel
Save