21 changed files with 600 additions and 1629 deletions
Binary file not shown.
@ -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> |
|||
@ -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> |
|||
@ -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> |
|||
@ -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> |
|||
@ -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> |
|||
@ -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> |
|||
@ -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> |
|||
@ -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' |
|||
@ -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> |
|||
@ -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> |
|||
@ -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> |
|||
@ -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…
Reference in new issue